当前位置: 移动技术网 > IT编程>移动开发>Android > Android应用框架之应用启动过程详解

Android应用框架之应用启动过程详解

2019年07月24日  | 移动技术网IT编程  | 我要评论

程小烦,郭mini露点,爱滋病初期症状

在android的应用框架中,activitymanagerservice是非常重要的一个组件,尽管名字叫做activitymanagerservice,但通过之前的博客介绍,我们知道,四大组件的创建都是有ams来完成的,其实不仅是应用程序中的组件,连android应用程序本身也是ams负责启动的。ams本身运行在一个独立的进程中,当系统决定要在一个新的进程中启动一个activity或者service时就会先启动这个进程。而ams启动进程的过程是从startprocesslocked启动的。

1.activitymanagerservice.startprocesslocked

public final class activitymanagerservice extends activitymanagernative 
    implements watchdog.monitor, batterystatsimpl.batterycallback { 
  ...... 
  private final void startprocesslocked(processrecord app, 
        string hostingtype, string hostingnamestr) { 
    ...... 
    try { 
      int uid = app.info.uid; 
      int[] gids = null; 
      try { 
        gids = mcontext.getpackagemanager().getpackagegids( 
          app.info.packagename); 
      } catch (packagemanager.namenotfoundexception e) { 
        ...... 
      } 
      ...... 
      int debugflags = 0; 
      ...... 
      int pid = process.start("android.app.activitythread", 
        msimpleprocessmanagement ? app.processname : null, uid, uid, 
        gids, debugflags, null); 
      ...... 
    } catch (runtimeexception e) { 
      ...... 
    } 
  } 
  ...... 
} 

可以看到,函数会调用process.start函数来创建一个进程,其中第一个参数”android.app.activitythread”是需要加载的类,而在完成这个类的加载之后就会运行activitythread.main函数。

2.process.start

public class process {
  ......
  public static final int start(final string processclass,
    final string nicename,
    int uid, int gid, int[] gids,
    int debugflags,
    string[] zygoteargs)
  {
    if (supportsprocesses()) {
      try {
        return startviazygote(processclass, nicename, uid, gid, gids,
          debugflags, zygoteargs);
      } catch (zygotestartfailedex ex) {
        ......
      }
    } else {
      ......
      return 0;
    }
  }
  ......
}

这个函数最后会调用startviazygote来创建进程,而zygote正是android孵化进程的服务,所有的进程都是通过zygotefork出来的,所以这里创建进程的任务又落到了zygote头上了。

3.process.startviazygote

public class process {
  ......
  private static int startviazygote(final string processclass,
      final string nicename,
      final int uid, final int gid,
      final int[] gids,
      int debugflags,
      string[] extraargs)
      throws zygotestartfailedex {
    int pid;

    synchronized(process.class) {
      arraylist<string> argsforzygote = new arraylist<string>();

      // --runtime-init, --setuid=, --setgid=,
      // and --setgroups= must go first
      argsforzygote.add("--runtime-init");
      argsforzygote.add("--setuid=" + uid);
      argsforzygote.add("--setgid=" + gid);
      if ((debugflags & zygote.debug_enable_safemode) != 0) {
        argsforzygote.add("--enable-safemode");
      }
      if ((debugflags & zygote.debug_enable_debugger) != 0) {
        argsforzygote.add("--enable-debugger");
      }
      if ((debugflags & zygote.debug_enable_checkjni) != 0) {
        argsforzygote.add("--enable-checkjni");
      }
      if ((debugflags & zygote.debug_enable_assert) != 0) {
        argsforzygote.add("--enable-assert");
      }

      //todo optionally enable debuger
      //argsforzygote.add("--enable-debugger");

      // --setgroups is a comma-separated list
      if (gids != null && gids.length > 0) {
        stringbuilder sb = new stringbuilder();
        sb.append("--setgroups=");

        int sz = gids.length;
        for (int i = 0; i < sz; i++) {
          if (i != 0) {
            sb.append(',');
          }
          sb.append(gids[i]);
        }

        argsforzygote.add(sb.tostring());
      }

      if (nicename != null) {
        argsforzygote.add("--nice-name=" + nicename);
      }

      argsforzygote.add(processclass);

      if (extraargs != null) {
        for (string arg : extraargs) {
          argsforzygote.add(arg);
        }
      }
      pid = zygotesendargsandgetpid(argsforzygote);
    }
  }
  ......
}

函数里面最为重要的工作就是组装argsforzygote参数,这些参数将告诉zygote具体的启动选项,例如”–runtime-init”就表示要为新启动的运行程序初始化运行库。然后调用zygotesendandgetpid函数进一步操作。

4.process.zygotesendandgetpid

public class process {
  ......

  private static int zygotesendargsandgetpid(arraylist<string> args)
      throws zygotestartfailedex {
    int pid;

    openzygotesocketifneeded();

    try {
      /**
      * see com.android.internal.os.zygoteinit.readargumentlist()
      * presently the wire format to the zygote process is:
      * a) a count of arguments (argc, in essence)
      * b) a number of newline-separated argument strings equal to count
      *
      * after the zygote process reads these it will write the pid of
      * the child or -1 on failure.
      */

      szygotewriter.write(integer.tostring(args.size()));
      szygotewriter.newline();

      int sz = args.size();
      for (int i = 0; i < sz; i++) {
        string arg = args.get(i);
        if (arg.indexof('\n') >= 0) {
          throw new zygotestartfailedex(
            "embedded newlines not allowed");
        }
        szygotewriter.write(arg);
        szygotewriter.newline();
      }

      szygotewriter.flush();

      // should there be a timeout on this?
      pid = szygoteinputstream.readint();

      if (pid < 0) {
        throw new zygotestartfailedex("fork() failed");
      }
    } catch (ioexception ex) {
      ......
    }
    return pid;
  }
  ......
}

这里的szygotewriter

是一个socket写入流,是由openzygotesocketifneeded函数打开的。而这个socket由frameworks/base/core/java/com/android/internal/os/zygoteinit.java文件中的zygoteinit类在runselectloopmode函数侦听的。这个类会返回一个zygoteconnection实例,并执行zygoteconnection的runonce函数。

5.zygoteconnection.runonce

class zygoteconnection {
  ......

  boolean runonce() throws zygoteinit.methodandargscaller {
    string args[];
    arguments parsedargs = null;
    filedescriptor[] descriptors;

    try {
      args = readargumentlist();
      descriptors = msocket.getancillaryfiledescriptors();
    } catch (ioexception ex) {
      ......
      return true;
    }

    ......

    /** the stderr of the most recent request, if avail */
    printstream newstderr = null;

    if (descriptors != null && descriptors.length >= 3) {
      newstderr = new printstream(
        new fileoutputstream(descriptors[2]));
    }

    int pid;

    try {
      parsedargs = new arguments(args);

      applyuidsecuritypolicy(parsedargs, peer);
      applydebuggersecuritypolicy(parsedargs);
      applyrlimitsecuritypolicy(parsedargs, peer);
      applycapabilitiessecuritypolicy(parsedargs, peer);

      int[][] rlimits = null;

      if (parsedargs.rlimits != null) {
        rlimits = parsedargs.rlimits.toarray(intarray2d);
      }

      pid = zygote.forkandspecialize(parsedargs.uid, parsedargs.gid,
        parsedargs.gids, parsedargs.debugflags, rlimits);
    } catch (illegalargumentexception ex) {
      ......
    } catch (zygotesecurityexception ex) {
      ......
    }

    if (pid == 0) {
      // in child
      handlechildproc(parsedargs, descriptors, newstderr);
      // should never happen
      return true;
    } else { /* pid != 0 */
      // in parent...pid of < 0 means failure
      return handleparentproc(pid, descriptors, parsedargs);
    }
  }
  ......
}

真正创建进程的代码在zygote.forkandspecialize,通过zygote来fork出一个新的进程作为应用进程。fork函数会有两个返回,其中一个在父进程,一个在子进程,其中自进程的进程号会为0,所以按照上面的代码,这里会执行handlechildproc。

6.zygoteconnection.handlechildproc

class zygoteconnection {
  ......
  private void handlechildproc(arguments parsedargs,
      filedescriptor[] descriptors, printstream newstderr)
      throws zygoteinit.methodandargscaller {
    ......
    if (parsedargs.runtimeinit) {
      runtimeinit.zygoteinit(parsedargs.remainingargs);
    } else {
      ......
    }
  }
  ......
}

因为在创建的时候传入了“–runtime-init”,所以这里会运行runtimeinit.zygoteinit。

public class runtimeinit {
  ......

  public static final void zygoteinit(string[] argv)
      throws zygoteinit.methodandargscaller {
    // todo: doing this here works, but it seems kind of arbitrary. find
    // a better place. the goal is to set it up for applications, but not
    // tools like am.
    system.setout(new androidprintstream(log.info, "system.out"));
    system.seterr(new androidprintstream(log.warn, "system.err"));

    commoninit();
    zygoteinitnative();

    int curarg = 0;
    for ( /* curarg */ ; curarg < argv.length; curarg++) {
      string arg = argv[curarg];

      if (arg.equals("--")) {
        curarg++;
        break;
      } else if (!arg.startswith("--")) {
        break;
      } else if (arg.startswith("--nice-name=")) {
        string nicename = arg.substring(arg.indexof('=') + 1);
        process.setargv0(nicename);
      }
    }

    if (curarg == argv.length) {
      slog.e(tag, "missing classname argument to runtimeinit!");
      // let the process exit
      return;
    }

    // remaining arguments are passed to the start class's static main

    string startclass = argv[curarg++];
    string[] startargs = new string[argv.length - curarg];

    system.arraycopy(argv, curarg, startargs, 0, startargs.length);
    invokestaticmain(startclass, startargs);
  }
  ......
}

这里有两个关键的函数调用,一个是zygoteinitnative函数调用,一个是invokestaticmain函数调用,前者就是执行binder驱动程序初始化的相关工作了,正是由于执行了这个工作,才使得进程中的binder对象能够顺利地进行binder进程间通信,而后一个函数调用,就是执行进程的入口函数,这里就是执行startclass类的main函数了,而这个startclass即是我们在step 1中传进来的”android.app.activitythread”值,表示要执行android.app.activitythread类的main函数。

7. zygote.invokestaticmain

public class zygoteinit {
  ......

  static void invokestaticmain(classloader loader,
      string classname, string[] argv)
      throws zygoteinit.methodandargscaller {
    class<?> cl;

    try {
      cl = loader.loadclass(classname);
    } catch (classnotfoundexception ex) {
      ......
    }

    method m;
    try {
      m = cl.getmethod("main", new class[] { string[].class });
    } catch (nosuchmethodexception ex) {
      ......
    } catch (securityexception ex) {
      ......
    }

    int modifiers = m.getmodifiers();
    ......

    /*
    * this throw gets caught in zygoteinit.main(), which responds
    * by invoking the exception's run() method. this arrangement
    * clears up all the stack frames that were required in setting
    * up the process.
    */
    throw new zygoteinit.methodandargscaller(m, argv);
  }
  ......
}

从代码中可以看到,通过classloader加载对应的android.app.activitythread类,然后再获取到对应的main函数句柄,最后调用该类的main函数。不过这里的调用方式比较有意思,不知直接调用,而是通过抛出一个异常。这样做的方式是为了清空堆栈,让系统认为新进程是从activitythread的main函数开始的。

8.activitythread.main

public final class activitythread {
  ......

  public static final void main(string[] args) {
    samplingprofilerintegration.start();

    process.setargv0("<pre-initialized>");

    looper.preparemainlooper();
    if (smainthreadhandler == null) {
      smainthreadhandler = new handler();
    }

    activitythread thread = new activitythread();
    thread.attach(false);

    if (false) {
      looper.mylooper().setmessagelogging(new
        logprinter(log.debug, "activitythread"));
    }
    looper.loop();

    if (process.supportsprocesses()) {
      throw new runtimeexception("main thread loop unexpectedly exited");
    }

    thread.detach();
    string name = (thread.minitialapplication != null)
      ? thread.minitialapplication.getpackagename()
      : "<unknown>";
    slog.i(tag, "main thread of " + name + " is now exiting");
  }

  ......
}

从这里我们可以看出,这个函数首先会在进程中创建一个activitythread对象,然后进入消息循环中,这样,我们以后就可以在这个进程中启动activity或者service了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网