Android FrameWork 学习

6.ActivityManagerService(四)App启动

2023-08-12  本文已影响0人  Tsm_2020

所有代码都是Android 11

整个Android 系统的SystemServer启动流程,和app 启动流程是非常类似的,只不过是参数不同,为了梳理整个的流程,下面我会从 zygote 的创建 加载 Vm 虚拟机开始分析整个流程

为了更好的让 zygote fork 子进程 需要将每个进程的都需要的一些关于native 层的准备在SystemServer 进程创建钱就准备好,整个流程大致如下

1.初始化运行时环境 RunTime

2 初始化Vm ,

  1. 加载jni

4.调用 zygoteInit.java 离开 native 层 ,去到java 层

我是从app_main.cpp开始分析的, 从 开机的 init 进程 进入到 加载Android 环境,
在 app_main.cpp 的main 方法中,先创建了一个AppRunTime 对象

int main(int argc, char* const argv[])
{

  AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
   ///省略部分代码.....
  while (i < argc) {
      const char* arg = argv[i++];
      if (strcmp(arg, "--zygote") == 0) {
          zygote = true;
          niceName = ZYGOTE_NICE_NAME;
      } 
  }

runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}

runtime.start 去到了 AndroidRunTime.cpp 中,在这里启动了Vm ,注册了jni ,然后离开了native层

创建jvm
  onVmCreated(env);

  注册jni
  if (startReg(env) < 0) { 
      ALOGE("Unable to register all android natives\n");
      return;
  }
//离开native 层
CallStaticVoidMethod(startClass, startMeth, strArray);

离开了native 层就进入到了zygoteInint.java , 此时 zygote 已经准备好了native 环境,看一下他的main 方法还做了哪些准备工作

初始化java 信息   
preload(bootTimingsTraceLog);

创建socket 服务器,为后续fork app 进程做准备
zygoteServer = new ZygoteServer(isPrimaryZygote);  

在这里可以看到他做了一个叫做preload 的方法,看一下都加载了什么

 static void preload(TimingsTraceLog bootTimingsTraceLog) {
     Log.d(TAG, "begin preload");
     bootTimingsTraceLog.traceBegin("BeginPreload");
     beginPreload();
     bootTimingsTraceLog.traceEnd(); // BeginPreload
     bootTimingsTraceLog.traceBegin("PreloadClasses");
     preloadClasses();// 加载系统类
     bootTimingsTraceLog.traceEnd(); // PreloadClasses
     bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
     cacheNonBootClasspathClassLoaders();// 没读明白这个是干什么的
     bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
     bootTimingsTraceLog.traceBegin("PreloadResources");
     preloadResources();// 加载系统资源
     bootTimingsTraceLog.traceEnd(); // PreloadResources
     Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
     nativePreloadAppProcessHALs();
     Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
     Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
     maybePreloadGraphicsDriver();//去了native 方法,
     Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
     preloadSharedLibraries();// 加载一些共享so库,其实就三个:android、compiler_rt、jnigraphics
     preloadTextResources();// 加载字体资源
     // Ask the WebViewFactory to do any initialization that must run in the zygote process,
     // for memory sharing purposes.
     WebViewFactory.prepareWebViewInZygote();// 加载webview相关资源
     endPreload();
     warmUpJcaProviders();// 初始化JCA安全相关的参数,干啥的还不清楚
     Log.d(TAG, "end preload");

     sPreloadComplete = true;
 }

初始化完资源并且建立了socket通道后,已经为 fork 子进程做好了准备,下面就开始fork 子进程,forkSystemServer

Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

             // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
             // child (system_server) process.
             if (r != null) {
                 r.run();
                 return;
             }
caller = zygoteServer.runSelectLoop(abiList);

在这里也开启一个looper ,等待fork其他子进程

接下来进入到Zygote 的 forkSystemServer 方法

 pid = Zygote.forkSystemServer(
                 parsedArgs.mUid, parsedArgs.mGid,
                 parsedArgs.mGids,
                 parsedArgs.mRuntimeFlags,
                 null,
                 parsedArgs.mPermittedCapabilities,
                 parsedArgs.mEffectiveCapabilities);

先说一下Zygote.forkSystemServer 也就是fork 进程的方法,这个方法比较有意思,一次调用他会返回两个返回值, 如果这个返回值是-1 ,那么证明fork 子进程失败, 如果返回的是0,那么说明回调的进程是子进程,如果返回的这个值大于0,回调的是fork进程

   if (pid == 0) { 
         if (hasSecondZygote(abiList)) {
             waitForSecondaryZygote(socketName);
         }

         zygoteServer.closeServerSocket();
         return handleSystemServerProcess(parsedArgs);
     }

这里面的判断就是如果当前进程是子进程,那么将 handleSystemServerProcess(parsedArgs); 这个方法的返回值返回,继续跟踪

上面创建反射的方法的过程
m = cl.getMethod("main", new Class[] { String[].class });
static class MethodAndArgsCaller implements Runnable {
     /** method to call */
     private final Method mMethod;
     /** argument array */
     private final String[] mArgs;
     public MethodAndArgsCaller(Method method, String[] args) {
         mMethod = method;
         mArgs = args;
     }
     public void run() {
         try {
             mMethod.invoke(null, new Object[] { mArgs });
         } catch (IllegalAccessException ex) {
             throw new RuntimeException(ex);
         } catch (InvocationTargetException ex) {
             Throwable cause = ex.getCause();
             if (cause instanceof RuntimeException) {
                 throw (RuntimeException) cause;
             } else if (cause instanceof Error) {
                 throw (Error) cause;
             }
             throw new RuntimeException(ex);
         }
     }

跟踪了好多层,最终返回是一个通过反射调用的 main 方法,那么在ZygoteInt mian 方法中 调用的 r.run() ,来反射到 SystemServer.main方法

我们在 Binder 的笔记中记录了剩余的过程,下面我就在分析一下SystemServer 的启动过程

SystemServer 的main 方法中new 了一个SystemServer ,并执行了他的run 方法,在这个方法里面创建SystemServiceManager用来启动 其他服务, 这个创建的过程大致分为了2种
1.该服务由于不需要binder 通信,那么创建的这个Service 则直接继承自 SystemService ,被 SystemServiceManager 创建
2.该服务需要实现binder通信,那么他就需要继承自对应的 IInterface.Stub ,实现服务端的代理,由于Java 的单继承模式,SystemService 则创建了一个静态内部类,让这个静态内部类在初始化的过程中创建该服务,

服务的启动方式是通过反射获取到服务,并将这个服务添加到SystemServiceManager 中 ,在启动后会回调该服务的onStart 方法,这个里面又产生了不一致的地方
1.ActivityTaskManagerService 在他的onStart 方法中会将自身添加到 ServiceManager 中来统一管理,
2.ActivityManagerService 在onStart 方法中并没有这么做,但是最后获取 AMS 也是通过ServiceManager来获取的,应该是在其他地方放进去的

创建完服务后,SystemServer 就开始进行Looper等待,

到了这里SystemServer 进程就初始化完毕了,比较有意思的是我在SystemServer 的run方法中发现他也为自己创建了 Context 上下文对象,我们来看看SystemServer 都干了什么

 private void createSystemContext() {
     ActivityThread activityThread = ActivityThread.systemMain();
     mSystemContext = activityThread.getSystemContext();
     mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

     final Context systemUiContext = activityThread.getSystemUiContext();
     systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
 }

 public static ActivityThread systemMain() {
     // The system process on low-memory devices do not get to use hardware
     // accelerated drawing, since this can add too much overhead to the
     // process.
     if (!ActivityManager.isHighEndGfx()) {
         ThreadedRenderer.disable(true);
     } else {
         ThreadedRenderer.enableForegroundTrimming();
     }
     ActivityThread thread = new ActivityThread();
     thread.attach(true, 0);
     return thread;
 }

在这里为SystemServer 也绑定了一个 ActivityThread ,这也验证了开启looper 的说法,如果不执行looper ,那么这个进程就会退出,整个系统就挂掉了

分析完了SystemServer 的启动流程,再去分析app 的启动流程就相对简单一点

  1. Lanucher 通过binder 调用 AMS 启动进程

2.AMS 通过 Socket 连接到 Zygote ,让Zygote fork 进程 ,并在子进程中通过反射方法调用 ActivityThread .main

  1. ActivityThread main 方法 创建了 Looper ,并绑定了ActivityThread ,执行 attach 方法 ,最后开启循环
         Looper.prepareMainLooper();
         //之前SystemServer调用attach传入的是true,这里到应用进程传入false就行
         ActivityThread thread = new ActivityThread();
         thread.attach(false, startSeq);
         if (sMainThreadHandler == null) {
             sMainThreadHandler = thread.getHandler();
         }
         if (false) {
             Looper.myLooper().setMessageLogging(new
                     LogPrinter(Log.DEBUG, "ActivityThread"));
         }
         // End of event ActivityThreadMain.
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         //一直循环,保障进程一直执行,如果退出,说明程序关闭
         Looper.loop();
    

4.在ActivityThread attach 方法中调用 使用 ams 通过binder 调用 attachApplication ,同时也为ViewRootImpl 注册了一个callback

//获取AMS的本地代理类
         final IActivityManager mgr = ActivityManager.getService();
         try {
             //通过Binder调用AMS的attachApplication方法
             mgr.attachApplication(mAppThread, startSeq);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }

     ViewRootImpl.ConfigChangedCallback configChangedCallback
             = (Configuration globalConfig) -> {
         synchronized (mResourcesManager) {
             // TODO (b/135719017): Temporary log for debugging IME service.
             if (Build.IS_DEBUGGABLE && mHasImeComponent) {
                 Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, "
                         + "config=" + globalConfig);
             }

             // We need to apply this change to the resources immediately, because upon returning
             // the view hierarchy will be informed about it.
             if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                     null /* compat */,
                     mInitialApplication.getResources().getDisplayAdjustments())) {
                 updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                         mResourcesManager.getConfiguration().getLocales());

                 // This actually changed the resources! Tell everyone about it.
                 if (mPendingConfiguration == null
                         || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
                     mPendingConfiguration = globalConfig;
                     sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                 }
             }
         }
     };
     ViewRootImpl.addConfigCallback(configChangedCallback);

  1. AMS 启动 application , app 启动完成 ,至于 AMS是如何 调度的Applicaiton ,我会在后面详细分析 AMS 的工作流程
上一篇下一篇

猜你喜欢

热点阅读