[关闭]
@chopsticks 2014-12-22T01:42:25.000000Z 字数 3992 阅读 2820

启动自定义进程

Android


基本背景

Android的应用程序进程启动,是通过启动Activity或启动Service来让ActivityManagerService创建新的进程。具体实现都是调用ActivityManagerService.startProcessLocked方法来根据ApplicationInfo、processName等信息创建专属进程。

在ActivityManagerService.startProcessLocked方法中,调用Proces.sStart实现进程的启动。对于启动Service和Activity而言,调用参数如下,参数具体意义参考Process.start

  1. Process.ProcessStartResult startResult = Process.start(
  2. "android.app.ActivityThread", //class
  3. app.processName,
  4. uid,
  5. uid,
  6. gids,
  7. debugFlags,
  8. mountExternal,
  9. app.info.targetSdkVersion,
  10. app.info.seinfo,
  11. null);
  12. 其中appprocessRecord

我们关注第一个传入的参数:android.app.ActivityThread,该类位于frameworks/base/core/java/android/app/ActivityThread.java,当进程创建完毕时会首先执行该进程类的static main()方法。需要注意的是,当start方法返回时,新进程已经运行。

我们需要考虑的时,如果我们自己构造一个类似android.app.ActivityThread的进程类,并指定给Process.start,则是否会被顺利执行并符合预期呢?答案是肯定的

Process start

  1. public static final ProcessStartResult start(
  2. final String processClass,
  3. final String niceName,
  4. int uid, int gid, int[] gids,
  5. int debugFlags,
  6. int mountExternal,
  7. int targetSdkVersion,
  8. String seInfo,
  9. String[] zygoteArgs)

processClass: The class to use as the process's main entry point

If processes are enabled, a new process is created and the static main() function of a processClass is executed there.

The process will continue running after this function returns.

Created with Raphaël 2.1.2Process.startProcess.startViaZygoteProcess.zygoteSendArgsAndGetResultsZygoteSocket

从流程看出,在Process类的几个方法中,仅仅是准备了参数字符串,然后将其通过socket发送个Zygote进程,让其fork新进程。并执行指定的类。

Zygote

ApplicationThread

mProcessNames

final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
mProcessNames是ActivityManagerService中维护的一个当前已经成功创建的ProcessRecord的MAP。其定义如下。源自google源码:framework/base/core/java/com/android/internal/app/ProcessMap.java

  1. package com.android.internal.app;
  2. import android.util.ArrayMap;
  3. import android.util.SparseArray;
  4. public class ProcessMap<E> {
  5. final ArrayMap<String, SparseArray<E>> mMap
  6. = new ArrayMap<String, SparseArray<E>>();
  7. public E get(String name, int uid) {
  8. SparseArray<E> uids = mMap.get(name);
  9. if (uids == null) return null;
  10. return uids.get(uid);
  11. }
  12. public E put(String name, int uid, E value) {
  13. SparseArray<E> uids = mMap.get(name);
  14. if (uids == null) {
  15. uids = new SparseArray<E>(2);
  16. mMap.put(name, uids);
  17. }
  18. uids.put(uid, value);
  19. return value;
  20. }
  21. public void remove(String name, int uid) {
  22. SparseArray<E> uids = mMap.get(name);
  23. if (uids != null) {
  24. uids.remove(uid);
  25. if (uids.size() == 0) {
  26. mMap.remove(name);
  27. }
  28. }
  29. }
  30. public ArrayMap<String, SparseArray<E>> getMap() {
  31. return mMap;
  32. }
  33. }

mPidsSelfLocked

final SparseArray<ProcessRecord> mPidsSelfLocked
mPidsSelfLocked维护了当前已经成功运行的进程的ProcessRecord.该列表与前文中关于mProcessNames不同地方在于,mProcessNames中的ProcessRecord并未一定用在某个特定进程上。


自定义进程类的构造

符合Process.start第一个参数procClass的基本相求,则需要static main()

进程启动超时的处理

由于启动进程时,替换了启动类ActivityThread,从而无法在新的进程中向AMS发送attach成功的信息,那么一定时间后,attach超时后会将新建的进程kill掉。所以需要进行启动超时的处理。

  1. final Handler mHandler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. switch (msg.what) {
  5. ...
  6. case PROC_START_TIMEOUT_MSG: {
  7. if (mDidDexOpt) {
  8. mDidDexOpt = false;
  9. Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
  10. nmsg.obj = msg.obj;
  11. mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
  12. return;
  13. }
  14. ProcessRecord app = (ProcessRecord)msg.obj;
  15. synchronized (ActivityManagerService.this) {
  16. processStartTimedOutLocked(app);
  17. }
  18. } break;

即首次调用则:mDidDexOpt 赋值为TRUE,并发送一个延时的相同MSG;再次进入时,则可以直接调用processStartTimedOutLocked,该函数则主要做的就是:从mPidsSelfLocked中移走该ProcessRecord,在输出attach失败的信息,然后kill该 attach超时的进程killUnneededProcessLocked(app, "start timeout");

如果我们需要防止被kill,则只需要在自己定义的startProcessLocked中取消发送timeout的消息即可。(同时需要在自己定义的startProcessLocked函数中取消remove 超时消息的处理。


添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注