@chopsticks
2014-12-21T17:42:25.000000Z
字数 3992
阅读 3121
Android
Android的应用程序进程启动,是通过启动Activity或启动Service来让ActivityManagerService创建新的进程。具体实现都是调用ActivityManagerService.startProcessLocked方法来根据ApplicationInfo、processName等信息创建专属进程。
在ActivityManagerService.startProcessLocked方法中,调用Proces.sStart实现进程的启动。对于启动Service和Activity而言,调用参数如下,参数具体意义参考Process.start。
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", //classapp.processName,uid,uid,gids,debugFlags,mountExternal,app.info.targetSdkVersion,app.info.seinfo,null);其中app为processRecord
我们关注第一个传入的参数:android.app.ActivityThread,该类位于frameworks/base/core/java/android/app/ActivityThread.java,当进程创建完毕时会首先执行该进程类的static main()方法。需要注意的是,当start方法返回时,新进程已经运行。
我们需要考虑的时,如果我们自己构造一个类似android.app.ActivityThread的进程类,并指定给Process.start,则是否会被顺利执行并符合预期呢?答案是肯定的
frameworks/base/core/java/android/os/Process.java
public static final ProcessStartResult start(final String processClass,final String niceName,int uid, int gid, int[] gids,int debugFlags,int mountExternal,int targetSdkVersion,String seInfo,String[] zygoteArgs)
Process.start方法的部分声明如下: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.
从流程看出,在Process类的几个方法中,仅仅是准备了参数字符串,然后将其通过socket发送个Zygote进程,让其fork新进程。并执行指定的类。
final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
mProcessNames是ActivityManagerService中维护的一个当前已经成功创建的ProcessRecord的MAP。其定义如下。源自google源码:framework/base/core/java/com/android/internal/app/ProcessMap.java
package com.android.internal.app;import android.util.ArrayMap;import android.util.SparseArray;public class ProcessMap<E> {final ArrayMap<String, SparseArray<E>> mMap= new ArrayMap<String, SparseArray<E>>();public E get(String name, int uid) {SparseArray<E> uids = mMap.get(name);if (uids == null) return null;return uids.get(uid);}public E put(String name, int uid, E value) {SparseArray<E> uids = mMap.get(name);if (uids == null) {uids = new SparseArray<E>(2);mMap.put(name, uids);}uids.put(uid, value);return value;}public void remove(String name, int uid) {SparseArray<E> uids = mMap.get(name);if (uids != null) {uids.remove(uid);if (uids.size() == 0) {mMap.remove(name);}}}public ArrayMap<String, SparseArray<E>> getMap() {return mMap;}}
final SparseArray<ProcessRecord> mPidsSelfLocked
mPidsSelfLocked维护了当前已经成功运行的进程的ProcessRecord.该列表与前文中关于mProcessNames不同地方在于,mProcessNames中的ProcessRecord并未一定用在某个特定进程上。
符合Process.start第一个参数procClass的基本相求,则需要static main()
由于启动进程时,替换了启动类ActivityThread,从而无法在新的进程中向AMS发送attach成功的信息,那么一定时间后,attach超时后会将新建的进程kill掉。所以需要进行启动超时的处理。
实现:
step1: 进程启动时,在调用的第二个startProcessLocked(arg1, arg2,arg3)中,其中存在有如下代码段:
synchronized (mPidsSelfLocked) {this.mPidsSelfLocked.put(startResult.pid, app);Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);msg.obj = app;mHandler.sendMessageDelayed(msg, startResult.usingWrapper?PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);}
可以看到发出了消息PROC_START_TIMEOUT_MSG。
step 2: 那么在AMS中对应的Handle对该消息的处理有如下代码:
final Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {...case PROC_START_TIMEOUT_MSG: {if (mDidDexOpt) {mDidDexOpt = false;Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);nmsg.obj = msg.obj;mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);return;}ProcessRecord app = (ProcessRecord)msg.obj;synchronized (ActivityManagerService.this) {processStartTimedOutLocked(app);}} break;
即首次调用则:mDidDexOpt 赋值为TRUE,并发送一个延时的相同MSG;再次进入时,则可以直接调用processStartTimedOutLocked,该函数则主要做的就是:从mPidsSelfLocked中移走该ProcessRecord,在输出attach失败的信息,然后kill该 attach超时的进程:killUnneededProcessLocked(app, "start timeout");
如果我们需要防止被kill,则只需要在自己定义的startProcessLocked中取消发送timeout的消息即可。(同时需要在自己定义的startProcessLocked函数中取消remove 超时消息的处理。