6.ActivityManagerService(四)App启动流程AppThread 创建

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

推荐阅读更多精彩内容