Android6.0之AMS通过socket与zygote通信创建app进程

2024-03-25 03:59

本文主要是介绍Android6.0之AMS通过socket与zygote通信创建app进程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:https://blog.csdn.net/love000520/article/details/70230784

前面分析到了ActivityStackSupervisor类中的startActivityUncheckedLocked方法,该方法主要是为要启动的activity准备一个task:有可复用的task,就直接使用;没有的话,就先寻找一个合适的ActivityStack,移动到前台后创建一个新的Task.紧接着调用ActivityStack的startActivityLocked()方法继续启动.

ActivityStack的startActivityLocked()

首先分析参数:

1
2
3
4
5
6
final void startActivityLocked(
ActivityRecord r, // 要启动的activity
boolean newTask,//是否新建了task,传入的true
boolean doResume,// 是否执行resume,传入的true
boolean keepCurTransition,// 传入的fasle,当要从一个activity启动一个activity,而且启动这个activity时,设置了FLAG_ACTIVITY_CLEAR_TOP,传入true
Bundle options)

如果是新创建的task,这个task已经在ActivityStack的顶端,而且其所在的Activitystack也在绑定的屏幕的顶端:

1
2
3
4
5
6
7
8
9
10
11
12
// r.task就是在startActivityUncheckedLocked中创建的新的task的TaskRecord对象,取出来保存到rRask变量中
TaskRecord rTask = r.task;
final int taskId = rTask.taskId;
// 如果是新创建的task的话
// taskForIdLocked在历史栈中查询是否含有id号为目标类所在的栈id,如果有,表明目标类之前已经被创建过,现在开始复用该对象,属于非首次启动,
// newTask传递过来为true
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {// 将其移到activitystack的顶部,也就是mTaskHistory的尾部insertTaskAtTop(rTask, r);mWindowManager.moveTaskToTop(taskId);
}

如果不需要新创建task:(从launcher第一次启动app,会创建新的task,所以不走这块代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
TaskRecord task = null;
if (!newTask) {boolean startIt = true;// 从 mTaskHistory中找到启动这个activity的activity所在的taskfor (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {task = mTaskHistory.get(taskNdx);if (task.getTopActivity() == null) {// All activities in task are finishing.continue;}// 找到了if (task == r.task) {if (!startIt) {............ActivityOptions.abort(options);return;}break;}// 如果在前面的task中有全屏应用存在,例如播放器等,设置为false.else if (task.numFullscreen > 0) {startIt = false;}}
}

上面代码就是从activitystack的mTaskHistory中找到启动这个activity的activity的task.

如果找到的这个task不在ActivityStack的顶端,那就没必要让当前正在显示的activity执行onUserLeaving操作.

1
2
3
4
5
if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {mStackSupervisor.mUserLeaving = false;if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,"startActivity() behind front, mUserLeaving=false");}

 

接着把要启动的activity放入Task的顶端,并设置inHistory为true;

1
2
3
4
task = r.task;
task.addActivityToTop(r);
task.setFrontOfTask();
r.putInHistory();

下面WMS开始准备绘制activity以及切换Activity时的动画.略过:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if (!isHomeStack() || numActivities() > 0){...// 一个activity的UI界面要想再终端屏幕上显示出来,很重要的一点就是他必须向WMS中添加token,以便于WMS在启动窗口的时候能够找到它mWindowManager.addAppToken(task.mActivities.indexOf(r),r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,(r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);boolean doShow = true;if (newTask) {if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {// 处理FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,rest  taskresetTaskIfNeededLocked(r, r);// 得到rest task之后,task的顶端activity是否与要启动的activity一致doShow = topRunningNonDelayedActivityLocked(null) == r;}} else if (options != null && new ActivityOptions(options).getAnimationType()== ActivityOptions.ANIM_SCENE_TRANSITION) {doShow = false;}...
}else{}

上述代码中关键的一点是:当是新创建task的时候,此时这个task的affinity就是activity的taskAffinity.这个要启动activity就是这个task的root activity.

这时候如果flag中包含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那么就会寻找当前activitystack中所有task中是设置了允许TaskReparenting,而又与其启动者没有依赖关系的activity(activity的resultTo为空),查看他们指定的task是不是现在这个新创建的task,是的话移动到这个新创建的task中来.

Task的startActivityLocked()方法主要就是将要启动的Activity加入到task的顶部.如果传入的newTask为true,表明创建了新的task,这是还要检查是否进行rest task操作处理TaskReparenting;为false,表明没有创建task,而是将activity加入到启动他的activity所在的task中.然后把task调整到ActivityStack中的mTaskHistory的顶部.也就是将task移动到栈顶.然后调用

1
2
3
4
// 传入的为true
if (doResume) {mStackSupervisor.resumeTopActivitiesLocked(this, r, options);}

开始显示task顶部的activity(并不一定是要启动的activity).

ActivityStackSupervisor.resumeTopActivitiesLocked()方法

这里要说明下,当从launcher,也就是桌面切换到一个app的activity的时候,前面也说了如果这个app所在的activitystack和homestack处于同一个屏幕中,就要调用ActivityStackSupervisor.moveHomeStack方法,来移动homestack.(确切的是当调用Activitystack.moveToFront()方法时,会进行这样的操作.)这时,mFocusedStack就会发生变化了,之前mFocusedStack是mhomeStack.在moveHomeStack方法会将其设置为即将显示的activity所在的ActivityStack.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,Bundle targetOptions) {// 如果传入的ActivityStack为null,那么设置为当前处于前台的ActivityStackif (targetStack == null) {targetStack = mFocusedStack;}// Do targetStack first.boolean result = false;// 检查targetStack是否和mFocusedStack一致.这里是一致的.原因前面解释了.if (isFrontStack(targetStack)) {result = targetStack.resumeTopActivityLocked(target, targetOptions);}............return result;}

ActivityStack.resumeTopActivityLocked()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {// 如果当前正在resume顶端activity的话,那就直接返回falseif (mStackSupervisor.inResumeTopActivity) {// Don't even start recursing.return false;}boolean result = false;try {// Protect against recursion.mStackSupervisor.inResumeTopActivity = true;if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;mService.updateSleepIfNeededLocked();}result = resumeTopActivityInnerLocked(prev, options);} finally {mStackSupervisor.inResumeTopActivity = false;}return result;
}

实际上是调用resumeTopActivityInnerLocked()方法

ActivityStack.resumeTopActivityInnerLocked

方法代码又是很多……….看注释吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {if (DEBUG_LOCKSCREEN) mService.logLockScreen("");if (!mService.mBooting && !mService.mBooted) {// Not ready yet!return false;}ActivityRecord parent = mActivityContainer.mParentActivity;if ((parent != null && parent.state != ActivityState.RESUMED) ||!mActivityContainer.isAttachedLocked()) {// Do not resume this stack if its parent is not resumed.// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.return false;}

这里的操作还是比较简单的,首先查看系统是否启动完成了,否则就直接返回。如果启动当前activity的activity本身的状态不是RESUMED的话,那么不能启动activity,直接返回false。

接下来找到,要启动的activity,这里实际上就是task的顶端activity.经过前面的过程,当前前台的task的就是运行要启动的activity所需的task.但至于顶端是否是要启动的activity那就不一定了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// next就是要启动的activity
final ActivityRecord next = topRunningActivityLocked(null);final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;// prevTask就是要启动的activity所在的task
final TaskRecord prevTask = prev != null ? prev.task : null;// 没有要启动的activity,那就显示home
if (next == null) {........
}// 不需要延时resume
next.delayedResume = false;
// If the top activity is the resumed one, nothing to do.
// 如果显示的activity就是要启动的activity,那么直接返回false
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&mStackSupervisor.allResumedActivitiesComplete()) {............return false;
}
// 下面又是做了一些检查而已
// 其中在创建task的时候
//  taskType = APPLICATION_ACTIVITY_TYPE;
//  mTaskToReturnTo = HOME_ACTIVITY_TYPE;
// 所以isOverHomeStack返回true
if (prevTask != null && prevTask.stack == this &&prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();// 几乎都满足这个条件,而setFrontOfTask前面已经做过了if (prevTask == nextTask) {prevTask.setFrontOfTask();} else if (prevTask != topTask()) {// This task is going away but it was supposed to return to the home stack.// Now the task above it has to return to the home task instead.// 如果task销毁了,移动到homefinal int taskNdx = mTaskHistory.indexOf(prevTask) + 1;mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);} else if (!isOnHomeDisplay()) {return false;} else if (!isHomeStack()){..............}
}

接下来还是做检查:如果系统当前准备休眠或者关机,如果是的话,那么就放弃本次启动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
if (mService.isSleepingOrShuttingDown()&& mLastPausedActivity == next&& mStackSupervisor.allPausedActivitiesComplete()) {// Make sure we have executed any pending transitions, since there// should be nothing left to do at this point.mWindowManager.executeAppTransition();mNoAnimActivities.clear();ActivityOptions.abort(options);if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Going to sleep and all paused");if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return false;
}

还是做检查,检查这个activity的用户已经启动了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Make sure that the user who owns this activity is started.  If not,
// we will just leave it as is because someone should be bringing
// another user's activities to the top of the stack.
if (mService.mStartedUsers.get(next.userId) == null) {Slog.w(TAG, "Skipping resume of top activity " + next+ ": user " + next.userId + " is stopped");if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return false;
}// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);

如果当前启动的activity正在等待stop,那么就放弃stop直接启动。因为现在已经没有必要将它stop了。

如果我们当前正在pause一个activity,那么我们需要等到我们的pause动作完成了才能开始启动activity。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// We need to start pausing the current activity so the top one// can be resumed...boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);if (mResumedActivity != null) {if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Pausing " + mResumedActivity);pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);}if (pausing) {if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,"resumeTopActivityLocked: Skip resume: need to start pausing");// At this point we want to put the upcoming activity's process// at the top of the LRU list, since we know we will be needing it// very soon and it would be a waste to let it get killed if it// happens to be sitting towards the end.if (next.app != null && next.app.thread != null) {mService.updateLruProcessLocked(next.app, true, null);}if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return true;}

继续,如果activity所在的app进程已经启动,那么直接显示activity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
ActivityStack lastStack = mStackSupervisor.getLastStack();if (next.app != null && next.app.thread != null)
{if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);// This activity is now becoming visible.mWindowManager.setAppVisibility(next.appToken, true);..........mService.updateCpuStats();..........try {//这个activity还有等待返回的结果,先发送结果ArrayList<ResultInfo> a = next.results;if (a != null) {final int N = a.size();if (!next.finishing && N > 0) {if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,"Delivering results to " + next + ": " + a);next.app.thread.scheduleSendResult(next.appToken, a);}}// 此时,说明要启动的activity已经存在,直接回调应用的onNewIntent方法if (next.newIntents != null) {next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);}............//调用activity的onResumenext.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,mService.isNextTransitionForward(), resumeAnimOptions);mStackSupervisor.checkReadyForSleepLocked();if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next);} catch (Exception e) {..............}.............}else{// 如过activity所在的进程还没启动,那么就使用下面的方法启动app进程.mStackSupervisor.startSpecificActivityLocked(next, true, true);}

 

resumeTopActivityInnerLocked()方法代码很长,检查的代码太多了,其实主要做了如下工作:

  1. 如果要启动的activity所在的进程已经启动,那么调用应用的scheduleResumeActivity恢复activity即可(如果此activity已经存在,那么需要先scheduleNewIntent,也就是调用onNewIntent方法)

  2. 如果要启动的activity所在的app进程还没启动,那么调用mStackSupervisor.startSpecificActivityLocked启动app进程,第一次启动app时,符合这个逻辑.

ActivityStackSupervisor.startSpecificActivityLocked()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {// Is this activity's application already running?ProcessRecord app = mService.getProcessRecordLocked(r.processName,r.info.applicationInfo.uid, true);r.task.stack.setLaunchTime(r);// 第一次启动app时,肯定app进程还没启动if (app != null && app.thread != null) {.........}// 调用AMS的startProcessLocked创建成mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false, false, true);}

ActivityManagerService.startProcessLocked()方法

1
2
3
4
5
6
7
8
9
final ProcessRecord startProcessLocked(String processName,ApplicationInfo info, boolean knownToBeDead, int intentFlags,String hostingType, ComponentName hostingName, boolean allowWhileBooting,boolean isolated, boolean keepIfLarge) {return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,null /* crashHandler */);}

实际上调用另一个同名不同参的startProcessLocked方法,介绍一下参数的含义.

processNam,即将要创建的在这个app进程的名字.传入的要启动的activity:ActivityRecord的processName.在创建ActivityRecord时,其构造方法中惠根据传入的要启动额activity的信息ActivityInfo记录的从清单xml文件中获得的进程名字,没有显示指定的话,默认为app的包名;

info要启动的app的ApplicationInfo,也是通过要启动的activity的ActivityInfo中获取的;

knownToBeDead传入的true;

intentFlags传入的0;

hostingType 传入的”activity”;

hostingName 传入的启动这个activity的intent设置的组件名,其实就是:app包名+app主actyivity的类名;

allowWhileBooting 传入的fasle;

isolated传入的false,说明要去检查当前进程列表中是否存在一个同名的进程,有的话复用这个进程.

keepIfLarge传入的false;

接下来的参数是

1
2
3
4
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler)

多出来的:

isolatedUid 传入的 0;

abiOverride,entryPoint,entryPointArgs,crashHandler传入的均为null;

分析其代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {long startTime = SystemClock.elapsedRealtime();ProcessRecord app;// 传入的fale.那么要检查当前系统中是否存在同名进程,存在的话并不需要重新创建了,复用即可// 但要清除这个已经存在的进程的一些信息,比如crash的次数等.if (!isolated) {app = getProcessRecordLocked(processName, info.uid, keepIfLarge);....}else{app = null}........// 这里只考虑 app为null,也就是app进程没有被创建过if (app == null) {checkTime(startTime, "startProcess: creating new process record");app = newProcessRecordLocked(info, processName, isolated, isolatedUid);if (app == null) {Slog.w(TAG, "Failed making new process record for "+ processName + "/" + info.uid + " isolated=" + isolated);return null;}app.crashHandler = crashHandler;checkTime(startTime, "startProcess: done creating new process record");}startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);return (app.pid != 0) ? app : null;

newProcessRecordLocked代码就是创建一个ProcessRecord对象.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,boolean isolated, int isolatedUid) {String proc = customProcess != null ? customProcess : info.processName;BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();final int userId = UserHandle.getUserId(info.uid);int uid = info.uid;if (isolated) {.........}final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);if (!mBooted && !mBooting&& userId == UserHandle.USER_OWNER&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {// 如果xml中设置了persistent为true,那么这么这里也设置为truer.persistent = true;}// 将即将要新创建的进程名字加入到AMS的mProcessNames中addProcessNameLocked(r);return r;}

ProcessRecord是一个进程在AMS中的代表,也是AMS管理一个进程的数据结构,所以很有必要掌握其关键数据成员.

其构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ProcessRecord(BatteryStatsImpl _batteryStats, ApplicationInfo _info,String _processName, int _uid) {mBatteryStats = _batteryStats;info = _info;isolated = _info.uid != _uid;//传入的两者相等,所以为fasleuid = _uid;userId = UserHandle.getUserId(_uid);processName = _processName;pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.versionCode));maxAdj = ProcessList.UNKNOWN_ADJ;curRawAdj = setRawAdj = -100;curAdj = setAdj = -100;persistent = false;removed = false;lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
}

ProcessRecord

源码路径:

1
Android-6/frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java

一个APK文件运行时会对应一个进程,当然,多个APK文件也可以运行在同一个进程中。ProcessRecord正是AMS记录一个进程中相关信息的类,该类中内部变量可分为三个部分:

进程文件信息

也就是与该进程对应的APK文件的内部信息.比如:

1
2
3
4
5
6
ApplicationInfo info;String processName;//保存该进程中的所有APK文件包名
final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList = new ArrayMap<>();

其中ApplicationInfo类定义节选如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ApplicationInfo extends PackageItemInfo implements Parcelable {public String taskAffinity;// 任务栈名称public String permission;public String processName;public String className;...........public String sourceDir;
..................public String[] resourceDirs;
.....................public String[] sharedLibraryFiles;public String dataDir;public String nativeLibraryDir;.....................public String primaryCpuAbi;public String secondaryCpuAbi;public int uid;.............public int targetSdkVersion;public int versionCode;

进程的内存状态信息

这些信息将用于Linux系统的Out Of Memory(OOM)情况的处理,当发生系统内部不够用时,Linux系统会根据进程的内存状态信息,杀掉优先级比较低的进程。

1
2
3
4
5
6
7
8
int maxAdj;
int curAdj;
...
// 是否是被AMS主动杀掉的,而不是因为内存不足而被杀掉
boolean killedByAm;         // True when proc has been killed by activity manager, not for RAM
// 是否被杀掉
boolean killed;             // True once we know the process has been killed
....

变量中adj的含义是adjustment,即“调整值”

进程中包含的Activity,Provider,Service等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// all activities running in the process
final ArrayList<ActivityRecord> activities = new ArrayList<>();
// all ServiceRecord running in this process
final ArraySet<ServiceRecord> services = new ArraySet<>();
// services that are currently executing code (need to remain foreground).
final ArraySet<ServiceRecord> executingServices = new ArraySet<>();
// All ConnectionRecord this process holds
final ArraySet<ConnectionRecord> connections = new ArraySet<>();
// all IIntentReceivers that are registered from this process.
final ArraySet<ReceiverList> receivers = new ArraySet<>();
// class (String) -> ContentProviderRecord
final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>();
// All ContentProviderRecord process is using
final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>();

接着分析startProcessLocked

1
2
3
4
5
6
7
private final void startProcessLocked(ProcessRecord app, //前面创建的ProcessRecord对象String hostingType,// "activity"String hostingNameStr, // "app包名+主activity类名"String abiOverride,// nullString entryPoint,// nullString[] entryPointArgs)// null

这个方法很重要,代码也比较短,直接分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// 刚启动app时,pid为0,所以不满足条件
if (app.pid > 0 && app.pid != MY_PID) {}
....
// mProcessesOnHold记录的是系统为准备好时,就想运行的app,这里因为已经准备好了,所以从这里移除它
mProcessesOnHold.remove(app);
//更新cpu状态
updateCpuStats();try{...int uid = app.uid;int[] gids = null;// 该进程使用的外部存储int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;// 通过前面传入ProcessRecord构造方法参数可知,其为false,所以执行if (!app.isolated) {int[] permGids = null;try{// 得到pmsfinal IPackageManager pm = AppGlobals.getPackageManager();// 获取app拥有的权限组permGids = pm.getPackageGids(app.info.packageName, app.userId);  MountServiceInternal mountServiceInternal = LocalServices.getService(MountServiceInternal.class);mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,app.info.packageName);}catch{}/** Add shared application and profile GIDs so applications can share some* resources like shared libraries and access user-wide resources*/if (ArrayUtils.isEmpty(permGids)) {gids = new int[2];} else {gids = new int[permGids.length + 2];System.arraycopy(permGids, 0, gids, 2, permGids.length);}gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));// 从ActivityInfo中提取给进程设置的相关标志,zygote创建新城时需要用到int debugFlags = 0;if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;// Also turn on CheckJNI for debuggable apps. It's quite// awkward to turn on otherwise.debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;}// Run the app in safe mode if its manifest requests so or the// system is booted in safe mode.if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||mSafeMode == true) {debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;}if ("1".equals(SystemProperties.get("debug.checkjni"))) {debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;}String jitDebugProperty = SystemProperties.get("debug.usejit");if ("true".equals(jitDebugProperty)) {debugFlags |= Zygote.DEBUG_ENABLE_JIT;} else if (!"false".equals(jitDebugProperty)) {// If we didn't force disable by setting false, defer to the dalvik vm options.if ("true".equals(SystemProperties.get("dalvik.vm.usejit"))) {debugFlags |= Zygote.DEBUG_ENABLE_JIT;}}String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");if ("true".equals(genDebugInfoProperty)) {debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;}if ("1".equals(SystemProperties.get("debug.jni.logging"))) {debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;}if ("1".equals(SystemProperties.get("debug.assert"))) {debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;}// 提取进行运行时的abi,如:armeabi,armeabi-v7a等// 对于有so库的app来说,PMS会解析除这个变量String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;// 对于没有so库的app来说,设置为系统的主abiif (requiredAbi == null) {requiredAbi = Build.SUPPORTED_ABIS[0];}// 设置进程指令集,如arm,arm64,x86,mips等String instructionSet = null;if (app.info.primaryCpuAbi != null) {instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);}// 墙面获取到的信息,填充到ProcessRecord中,app.gids = gids;app.requiredAbi = requiredAbi;app.instructionSet = instructionSet;// 设置进程的入口点,也就是执行代码的入口点// 传入的为null,所以为trueboolean isActivityProcess = (entryPoint == null);// 设置进程入口点if (entryPoint == null)entryPoint = "android.app.ActivityThread";.......// 开始真正的创建进程Process.ProcessStartResult startResult = Process.start(entryPoint,app.processName, uid, uid, gids, debugFlags, mountExternal,app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,app.info.dataDir, entryPointArgs);
// 创建app进程的时候为false
if (app.isolated) {mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);}// 电源管理
mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);// 如果设置该变量为true,表明该进程要一直存在,当被杀死时,要被重新唤醒.所以加入watchdog中
if (app.persistent) {watchdog.getInstance().processStarted(app.processName, startResult.pid);}
......
// 继续初始化ProcessRecord,
app.setPid(startResult.pid);//前面创建进程时,返回了进程号pid
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
app.killed = false;
app.killedByAm = false;synchronized (mPidsSelfLocked) {
// 将App进程的ProcessRecord以其进程号为索引加入到AMS的mPidsSelfLocked中
// 后续ActivityThread.main中调用AMS的attachApplicationLocked()方法会以进程号,重新拿到其ProcessRecord
this.mPidsSelfLocked.put(startResult.pid, app);
// 前面设置了该变量为true
if (isActivityProcess) {// 向AMS发送PROC_START_TIMEOUT_MSG消息Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);msg.obj = app;mHandler.sendMessageDelayed(msg, startResult.usingWrapper? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}

startProcessLocked()方法的流程是:准备好启动进程的相关参数,例如进程权等,调用Process的start()方法来启动进程.启动进程后,利用返回的信息初始化ProcessRecord,比如拿到进程pid等.另外当进程需要常驻内存时,需要将其添加到watchdog中.

启动进程之后,AMS给自己发送一个PROC_START_TIMEOUT_MSG消息,这个消息用来防止进程启动时间超时.如果start()方法返回结果中usingWrapper为true,超时时间设置为1200秒,否则设置为10秒.如果时间到了进程还没启动AMS将弹出ANR对话框.

App进程启动后,会先执行ActivityThread.main()方法,该方法会调用AMS的attachApplicationLocked()方法,这个方法中会将这个PROC_START_TIMEOUT_MSG消息,从消息队列中移除.如果在规定的超时时间内没移除该消息,就会导致进程启动超时机制被触发.

Process.start()方法

源码位置:

1
Android-6/frameworks/base/core/java/android/os/Process.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static final ProcessStartResult start(final String processClass,//进程的入口点,android.app.ActivityThreadfinal String niceName,//进程的名字int uid, int gid, int[] gids,// 进程uid gid,权限相关int debugFlags, // app在清单文件中设置的进程相关标记 ,以及系统设置的进程标记,例如是否让VM执行checkjni等int mountExternal,// 外部存储相关int targetSdkVersion,// app中指定的targetSdkVersionString seInfo,//SElinux相关,设置进程安全上下文使用String abi,//进程abi,如armeabi,armeabi-v7a等String instructionSet,// 指令集.如arm,arm64,x86,mips等String appDataDir,//app数据沙箱目录String[] zygoteArgs //传入的为null) {try {return startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, mountExternal, targetSdkVersion, seInfo,abi, instructionSet, appDataDir, zygoteArgs);} catch (ZygoteStartFailedEx ex) {Log.e(LOG_TAG,"Starting VM process through Zygote failed");throw new RuntimeException("Starting VM process through Zygote failed", ex);}
}

在Process类的startViaZygote方法里,会计算启动应用进程用的各个参数,然后再调用zygoteSendArgsAndGetResult方法将这些参数通过socket发送给zygote进程,zygote进程会孵化出新的dalvik应用进程,然后告诉ActivityManagerService新启动的进程的pid。

Process.startViaZygote()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private static ProcessStartResult startViaZygote(final String processClass,final String niceName,final int uid, final int gid,final int[] gids,int debugFlags, int mountExternal,int targetSdkVersion,String seInfo,String abi,String instructionSet,String appDataDir,String[] extraArgs)throws ZygoteStartFailedEx {synchronized(Process.class) {ArrayList<String> argsForZygote = new ArrayList<String>();// 开始整理传入的参数argsForZygote.add("--runtime-args");argsForZygote.add("--setuid=" + uid);argsForZygote.add("--setgid=" + gid);if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {argsForZygote.add("--enable-jni-logging");}..........if (appDataDir != null) {argsForZygote.add("--app-data-dir=" + appDataDir);}.....argsForZygote.add(processClass);// 传入的为nullif (extraArgs != null) {for (String arg : extraArgs) {argsForZygote.add(arg);}}// 将这些参数通过socket发送给zygote进程,用来创建进程return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);}

其中openZygoteSocketIfNeeded()方法用来连接Zygote socket.从Android 5.0开始,Android开始支持64位系统.对于64位Android系统来说,存在两个zygote进程:

  1. 主zygote,对应的socket:/dev/socket/zygote

  2. 次zygote,对应的scoket:/dev/socket/zygote_secondary

至于主次zygote哪个对应于64位的zygote,哪个是32位的zygote.则有init进程解析相关rc文件决定.

连接zygote时,首先连接主zygote.主次zygote一个是64,一个是32,所以支持的abi肯定不同.根据当前的abi来选择与zygote32还是zygote64来进行通信。

openZygoteSocketIfNeeded()方法返回值是ZygoteState对象

1
2
3
4
5
6
public static class ZygoteState {final LocalSocket socket;final DataInputStream inputStream;final BufferedWriter writer;final List<String> abiList;.......

Process.zygoteSendArgsAndGetResult()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private static ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, ArrayList<String> args)throws ZygoteStartFailedEx {try {final BufferedWriter writer = zygoteState.writer;final DataInputStream inputStream = zygoteState.inputStream;// 先发参数所占字节数大小writer.write(Integer.toString(args.size()));// 开始新的一行(相当于发了"\n")writer.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");}// 发送一个参数writer.write(arg);// 开始新的一行(相当于发了"\n")writer.newLine();}// 将信息发送给zygotewriter.flush();ProcessStartResult result = new ProcessStartResult();// 通过socket读取zygote的返回信息(阻塞到有数为止)// zygote先发送创建的进程的pid,为-1表示创建失败result.pid = inputStream.readInt();if (result.pid < 0) {throw new ZygoteStartFailedEx("fork() failed");}// 然后发送的是一个boolean值,于超时间的设定有关result.usingWrapper = inputStream.readBoolean();return result;} catch (IOException ex) {zygoteState.close();throw new ZygoteStartFailedEx(ex);}}

Zygote孵化App进程

zygote进程将ZygoteInit作为启动类,会执行它的main方法,先注册Zygote Socket,然后调用runSelectLoop方法,runSelectLoop方法会调用方法在Zygote Socket上监听请求,如果别的进程通过Zygote Socket请求孵化进程,则孵化进程。

ZygoteInit.main:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String argv[]) {try {runSelectLoop(abiList);....} catch (MethodAndArgsCaller caller) {caller.run();} catch (RuntimeException ex) {closeServerSocket();throw ex;}
}

runSelectLoop()方法会抛出异常MethodAndArgsCaller,从而进入caller.run(),也就是MethodAndArgsCaller.run()方法。

ZygoteInit.runSelectLoop()

这个方法是zygote用来监听和处理创建应用进程的请求.注意此方法是一个死循环!!!通过ZygoteConnection.runOnce()抛出MethodAndArgsCaller异常返回ZygoteInit.main中.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();// 将 zygote socket 的 fd加入数组fds.add(sServerSocket.getFileDescriptor());peers.add(null);// 这里使用到了linux的poll机制while (true) {StructPollfd[] pollFds = new StructPollfd[fds.size()];for (int i = 0; i < pollFds.length; ++i) {pollFds[i] = new StructPollfd();pollFds[i].fd = fds.get(i);pollFds[i].events = (short) POLLIN;}try {Os.poll(pollFds, -1);} catch (ErrnoException ex) {throw new RuntimeException("poll failed", ex);}for (int i = pollFds.length - 1; i >= 0; --i) {//采用I/O多路复用机制,当客户端发出连接请求或者数据处理请求时,跳过continue,执行后面的代码if ((pollFds[i].revents & POLLIN) == 0) {continue;}if (i == 0) {//表示zygote socket中有连接到来,那么就要创建客户端连接// 实际上就是执行socket accept操作// 然后把创建的这个连接也加入到监听数组中,索引肯定大于0了// 那么一旦这个连接中有数据来了,i肯定大于0ZygoteConnection newPeer = acceptCommandPeer(abiList);peers.add(newPeer);fds.add(newPeer.getFileDesciptor());} else {//调用ZygoteConnection.runOnce()处理客户端数据事务boolean done = peers.get(i).runOnce();// 处理完之后,断开连接,并且不在监听这个连接if (done) {peers.remove(i);fds.remove(i);}}}}
}

ZygoteConnection.runOnce()

这个方法首先肯定是先从 socket接受传递过来的启动进程的线骨干参数.然后解析参数.检查权限,创建进程,然后处理父子进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {String args[];Arguments parsedArgs = null;FileDescriptor[] descriptors;try {//接受参数args = readArgumentList();descriptors = mSocket.getAncillaryFileDescriptors();} catch (IOException ex) {........................}.......try {// 解析参数parsedArgs = new Arguments(args);.......// 权限检查applyUidSecurityPolicy(parsedArgs, peer);applyInvokeWithSecurityPolicy(parsedArgs, peer);applyDebuggerSystemProperty(parsedArgs);applyInvokeWithSystemProperty(parsedArgs);.....pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);}catch{......}try {if (pid == 0) {// in child// 创建的app进程IoUtils.closeQuietly(serverPipeFd);serverPipeFd = null;handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);// should never get here, the child is expected to either// throw ZygoteInit.MethodAndArgsCaller or exec().return true;} else {// in parent...pid of < 0 means failure// zygote进程IoUtils.closeQuietly(childPipeFd);childPipeFd = null;return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}}

Zygote.forkAndSpecialize()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,String instructionSet, String appDataDir) {VM_HOOKS.preFork();int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,instructionSet, appDataDir);// Enable tracing as soon as possible for the child process.if (pid == 0) {Trace.setTracingEnabled(true);// Note that this event ends at the end of handleChildProc,Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");}VM_HOOKS.postForkCommon();return pid;
}

从代码中可知zygote孵化进程还是依靠的jni native方法完成的.

在真正孵化进程之前,要做一些前期工作,比如暂停zygote中运行的线程,从而提高fork效率.这些是由VM_HOOKS.preFork()完成的.

1
2
3
4
5
6
7
8
9
10
11
public void preFork() {Daemons.stop();//停止4个Daemon子线程waitUntilAllThreadsStopped();//等待所有子线程结束token = nativePreFork();//完成gc堆的初始化工作
}
public static void stop() {HeapTaskDaemon.INSTANCE.stop(); //Java堆整理线程ReferenceQueueDaemon.INSTANCE.stop(); //引用队列线程FinalizerDaemon.INSTANCE.stop(); //析构线程FinalizerWatchdogDaemon.INSTANCE.stop(); //析构监控线程
}

守护线程Stop方式是先调用目标线程interrrupt()方法,然后再调用目标线程join()方法,等待线程执行完成.

Zygote.nativeForkAndSpecialize()方法

源码路径:

1
Android-6/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,jint debug_flags, jobjectArray rlimits,jint mount_external, jstring se_info, jstring se_name,jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {// Grant CAP_WAKE_ALARM to the Bluetooth process.jlong capabilities = 0;if (uid == AID_BLUETOOTH) {capabilities |= (1LL << CAP_WAKE_ALARM);}return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,rlimits, capabilities, capabilities, mount_external, se_info,se_name, false, fdsToClose, instructionSet, appDataDir);
}

实际上调用下面的方法创建进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,jint debug_flags, jobjectArray javaRlimits,jlong permittedCapabilities, jlong effectiveCapabilities,jint mount_external,jstring java_se_info, jstring java_se_name,bool is_system_server, jintArray fdsToClose,jstring instructionSet, jstring dataDir) {//设置子进程的signal信号处理函数SetSigChldHandler();// fork进程// 父进程中,fork返回新创建的子进程的pid;// 子进程中,fork返回0// 执行完这句代码,后面的代码父子进程都会执行,所以要根据返回值做不同处理.pid_t pid = fork();if (pid == 0) {// app进程gMallocLeakZygoteChild = 1;DetachDescriptors(env, fdsToClose);// Keep capabilities across UID change, unless we're staying root.// 使用linux capabilities 权限机制,root进程不使用if (uid != 0) {EnableKeepCapabilities(env);}// 由于前面开始了capabilities机制,所以可以放弃某些app进程不该拥有的能力了DropCapabilitiesBoundingSet(env);// x86架构运行arm文件时,需要一个bridgebool use_native_bridge = !is_system_server && (instructionSet != NULL)&& android::NativeBridgeAvailable();if (use_native_bridge) {ScopedUtfChars isa_string(env, instructionSet);use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());}if (use_native_bridge && dataDir == NULL) {use_native_bridge = false;ALOGW("Native bridge will not be used because dataDir == NULL.");}// 进程外置外部存储// 6.0中,因为允许动态授权权限,比如说app申请了对外部存储的读写权限,可能用户之后会关闭写权限等// 所以6.0中,改变了对外部存储的管理策略,这个以后单独讲// 这里只需要直到根据mount_external// 有三个挂在点:/mnt/runtime/default,storageSource = "/mnt/runtime/read",storageSource = "/mnt/runtime/write"// 6.0之前,都是直接指向外部存储的if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) {ALOGW("Failed to mount emulated storage: %s", strerror(errno));if (errno == ENOTCONN || errno == EROFS) {} else {ALOGE("Cannot continue without emulated storage");RuntimeAbort(env);}}if (!is_system_server) {//对于非system_server子进程,则创建进程组// 创建文件夹/acct/uid_<uid>/,权限0750,system:system// 创建文件夹/acct/uid_<uid>/pid_<pid>,权限0750,system:system// open文件/acct/uid_<uid>/pid_<pid>/cgroup.procs,记录进程号int rc = createProcessGroup(uid, getpid());if (rc != 0) {.......................}}//设置设置groupSetGids(env, javaGids);//设置资源limitSetRLimits(env, javaRlimits);if (use_native_bridge) {ScopedUtfChars isa_string(env, instructionSet);ScopedUtfChars data_dir(env, dataDir);android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());}int rc = setresgid(gid, gid, gid);if (rc == -1) {ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));RuntimeAbort(env);}rc = setresuid(uid, uid, uid);if (rc == -1) {ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));RuntimeAbort(env);}if (NeedsNoRandomizeWorkaround()) {// Work around ARM kernel ASLR lossage (http://b/5817320).int old_personality = personality(0xffffffff);int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);if (new_personality == -1) {ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));}}// 设置能力,除了蓝颜进程外,其他app进程,permittedCapabilities为0SetCapabilities(env, permittedCapabilities, effectiveCapabilities);//设置调度策略SetSchedulerPolicy(env);const char* se_info_c_str = NULL;// PMS在app安装的时候,就会记录seinfo.第三方app一般都为default.ScopedUtfChars* se_info = NULL;if (java_se_info != NULL) {se_info = new ScopedUtfChars(env, java_se_info);se_info_c_str = se_info->c_str();if (se_info_c_str == NULL) {ALOGE("se_info_c_str == NULL");RuntimeAbort(env);}}const char* se_name_c_str = NULL;ScopedUtfChars* se_name = NULL;if (java_se_name != NULL) {se_name = new ScopedUtfChars(env, java_se_name);se_name_c_str = se_name->c_str();if (se_name_c_str == NULL) {ALOGE("se_name_c_str == NULL");RuntimeAbort(env);}}//设置selinux上下文rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);if (rc == -1) {ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,is_system_server, se_info_c_str, se_name_c_str);RuntimeAbort(env);}// Make it easier to debug audit logs by setting the main thread's name to the// nice name rather than "app_process".if (se_info_c_str == NULL && is_system_server) {se_name_c_str = "system_server";}// 第三方app为defaultif (se_info_c_str != NULL) {SetThreadName(se_name_c_str);}delete se_info;delete se_name;//在Zygote子进程中,设置信号SIGCHLD的处理器恢复为默认行为UnsetSigChldHandler();//调用zygote.callPostForkChildHooks()env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,is_system_server ? NULL : instructionSet);if (env->ExceptionCheck()) {ALOGE("Error calling post fork hooks.");RuntimeAbort(env);}} else if (pid > 0) {// the parent process}return pid;
}
1
2
3
4
5
6
7
8
private static void callPostForkChildHooks(int debugFlags, String instructionSet) {VM_HOOKS.postForkChild(debugFlags, instructionSet);}public void postForkChild(int debugFlags, String instructionSet) {nativePostForkChild(token, debugFlags, instructionSet);Math.setRandomSeedInternal(System.currentTimeMillis());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,jstring instruction_set) {Thread* thread = reinterpret_cast<Thread*>(token);//设置新进程的主线程idthread->InitAfterFork();..if (instruction_set != nullptr) {ScopedUtfChars isa_string(env, instruction_set);InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;if (isa != kNone && isa != kRuntimeISA) {action = Runtime::NativeBridgeAction::kInitialize;}//【见流程6-2-2-1-1-1】Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());} else {Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {is_zygote_ = false;if (is_native_bridge_loaded_) {switch (action) {case NativeBridgeAction::kUnload:UnloadNativeBridge(); //卸载用于跨平台的桥连库is_native_bridge_loaded_ = false;break;case NativeBridgeAction::kInitialize:InitializeNativeBridge(env, isa);//初始化用于跨平台的桥连库break;}}//创建Java堆处理的线程池heap_->CreateThreadPool();//重置gc性能数据,以保证进程在创建之前的GCs不会计算到当前app上。heap_->ResetGcPerformanceInfo();if (jit_.get() == nullptr && jit_options_->UseJIT()) {//当flag被设置,并且还没有创建JIT时,则创建JITCreateJit();}//设置信号处理函数StartSignalCatcher();//启动JDWP线程,当命令debuger的flags指定"suspend=y"时,则暂停runtimeDbg::StartJdwp();
}

继续看Zygote.forkAndSpecialize()

会调用:

1
VM_HOOKS.postForkCommon();

 

1
2
3
4
5
6
7
8
9
public void postForkCommon() {Daemons.start();
}
public static void start() {ReferenceQueueDaemon.INSTANCE.start();FinalizerDaemon.INSTANCE.start();FinalizerWatchdogDaemon.INSTANCE.start();HeapTaskDaemon.INSTANCE.start();
}

VM_HOOKS.postForkCommon的主要功能是在fork新进程后,启动Zygote的4个Daemon线程,java堆整理,引用队列,以及析构线程(前面暂停了)。

ZygoteConnection.handleChildProc()–子进程初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private void handleChildProc(Arguments parsedArgs,FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)throws ZygoteInit.MethodAndArgsCaller {//关闭Zygote的socket两端的连接closeSocket();ZygoteInit.closeServerSocket();// 关闭从zygote继承的文件描述if (descriptors != null) {try {Os.dup2(descriptors[0], STDIN_FILENO);Os.dup2(descriptors[1], STDOUT_FILENO);Os.dup2(descriptors[2], STDERR_FILENO);for (FileDescriptor fd: descriptors) {IoUtils.closeQuietly(fd);}newStderr = System.err;} catch (ErrnoException ex) {Log.e(TAG, "Error reopening stdio", ex);}}if (parsedArgs.niceName != null) {//设置进程名Process.setArgV0(parsedArgs.niceName);}if (parsedArgs.invokeWith != null) {...........................} else {//执行ActivityThread.mainRuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs, null);}
}

RuntimeInit.ZygoteInit()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)throws ZygoteInit.MethodAndArgsCaller {if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");//重定向log输出redirectLogStreams();//一些初始化commonInit();// zygote初始化nativeZygoteInit();// 应用初始化applicationInit(targetSdkVersion, argv, classLoader);
}

RuntimeInit.commonInit()方法

commonInit()方法主要进行一些简单初始化:设置异常处理,设置时区,重置Android log 系统,设置http.agent属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static final void commonInit() {// 设置默认的未捕捉异常处理方法// app也可以调用这个方法设置自己的处理方法,例如在处理方法中把产生的异常信息发送到公司服务器中Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());// 设置市区,中国时区为"Asia/Shanghai"TimezoneGetter.setInstance(new TimezoneGetter() {@Overridepublic String getId() {return SystemProperties.get("persist.sys.timezone");}});TimeZone.setDefault(null);//重置log配置LogManager.getLogManager().reset();new AndroidConfig();// 设置默认的HTTP User-agent格式,用于 HttpURLConnection。String userAgent = getDefaultUserAgent();System.setProperty("http.agent", userAgent);// 设置socket的tag,用于网络流量统计NetworkManagementSocketTagger.install();
}

RuntimeInit.nativeZygoteInit()方法

源码路径:

1
Android-6/frameworks/base/core/jni/AndroidRuntime.cpp
Android-6/frameworks/base/cmds/app_process/App_main.cpp
1
2
3
4
5
6
7
8
9
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{gCurRuntime->onZygoteInit(); //此处的gCurRuntime为AppRuntime,是在AndroidRuntime.cpp中定义的
}
virtual void onZygoteInit()
{sp<ProcessState> proc = ProcessState::self();proc->startThreadPool(); //启动新binder线程
}

ProcessState::self()是单例模式,主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作。startThreadPool()是创建一个新的binder线程,不断进行talkWithDriver().

该方法主要进行binder的初始化,这样app就可以使用binder了.

RuntimeInit.applicationInit()方法

开始指向ActivityThread.main().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)throws ZygoteInit.MethodAndArgsCaller {//true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用nativeSetExitWithoutCleanup(true);//设置虚拟机的内存利用率参数值为0.75VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);final Arguments args;try {args = new Arguments(argv);} catch (IllegalArgumentException ex) {Slog.e(TAG, ex.getMessage());// let the process exitreturn;}// Remaining arguments are passed to the start class's static maininvokeStaticMain(args.startClass, args.startArgs, classLoader);}

RuntimeInit.invokeStaticMain()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)throws ZygoteInit.MethodAndArgsCaller {Class<?> cl;try {// 传入的classLoader为nullcl = Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {throw new RuntimeException("Missing class when invoking static main " + className, ex);}// 找到main方法Method m;try {m = cl.getMethod("main", new Class[] { String[].class });} catch (NoSuchMethodException ex) {throw new RuntimeException( "Missing static main on " + className, ex);} catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}// main方法必须是static public类型的int modifiers = m.getModifiers();if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {throw new RuntimeException("Main method is not public and static on " + className);}//通过抛出异常,回到ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率。// m就是找到的main方法throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

MethodAndArgsCaller.run()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void run() {try {// mMethod就是ActivityThread.main方法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);}}

到此位置app的进程算是创建完毕了,进程执行的第一个方法也找到是谁了.

这篇关于Android6.0之AMS通过socket与zygote通信创建app进程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/843788

相关文章

ESP32 esp-idf esp-adf环境安装及.a库创建与编译

简介 ESP32 功能丰富的 Wi-Fi & 蓝牙 MCU, 适用于多样的物联网应用。使用freertos操作系统。 ESP-IDF 官方物联网开发框架。 ESP-ADF 官方音频开发框架。 文档参照 https://espressif-docs.readthedocs-hosted.com/projects/esp-adf/zh-cn/latest/get-started/index

通信系统网络架构_2.广域网网络架构

1.概述          通俗来讲,广域网是将分布于相比局域网络更广区域的计算机设备联接起来的网络。广域网由通信子网于资源子网组成。通信子网可以利用公用分组交换网、卫星通信网和无线分组交换网构建,将分布在不同地区的局域网或计算机系统互连起来,实现资源子网的共享。 2.网络组成          广域网属于多级网络,通常由骨干网、分布网、接入网组成。在网络规模较小时,可仅由骨干网和接入网组成

ROS话题通信流程自定义数据格式

ROS话题通信流程自定义数据格式 需求流程实现步骤定义msg文件编辑配置文件编译 在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如:

Python应用开发——30天学习Streamlit Python包进行APP的构建(9)

st.area_chart 显示区域图。 这是围绕 st.altair_chart 的语法糖。主要区别在于该命令使用数据自身的列和指数来计算图表的 Altair 规格。因此,在许多 "只需绘制此图 "的情况下,该命令更易于使用,但可定制性较差。 如果 st.area_chart 无法正确猜测数据规格,请尝试使用 st.altair_chart 指定所需的图表。 Function signa

vscode-创建vue3项目-修改暗黑主题-常见错误-element插件标签-用法涉及问题

文章目录 1.vscode创建运行编译vue3项目2.添加项目资源3.添加element-plus元素4.修改为暗黑主题4.1.在main.js主文件中引入暗黑样式4.2.添加自定义样式文件4.3.html页面html标签添加样式 5.常见错误5.1.未使用变量5.2.关闭typescript检查5.3.调试器支持5.4.允许未到达代码和未定义代码 6.element常用标签6.1.下拉列表

使用JWT进行安全通信

在现代Web应用中,安全通信是至关重要的。JSON Web Token(JWT)是一种流行的安全通信方式,它允许用户和服务器之间安全地传输信息。JWT是一种紧凑的、URL安全的表示方法,用于在两方之间传输信息。本文将详细介绍JWT的工作原理,并提供代码示例帮助新人理解和实现JWT。 什么是JWT? JWT是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以JSO

【Qt6.3 基础教程 17】 Qt布局管理详解:创建直观和响应式UI界面

文章目录 前言布局管理的基础为什么需要布局管理器? 盒布局:水平和垂直排列小部件示例:创建水平盒布局 栅格布局:在网格中对齐小部件示例:创建栅格布局 表单布局:为表单创建标签和字段示例:创建表单布局 调整空间和伸缩性示例:增加弹性空间 总结 前言 当您开始使用Qt设计用户界面(UI)时,理解布局管理是至关重要的。布局管理不仅关系到UI的外观,更直接影响用户交互的体验。本篇博

同城跑腿APP开发,随叫随到超方便!

随着移动互联网的发展和人们生活节奏的加快,越来越多的人们没有闲暇的时间来做一些繁琐的事情,比如说买药、挂号、排队、送花、取文件等等。如果没有时间去处理这些事情怎么办?开发同城跑腿APP,提供跑腿服务,随时办事随时下单,只需在手机上轻轻一点,就可完成跑腿需求。 首先,跑腿小程序有几种开发方式。第一种是自己组建开发,这种方式比较适合有软件开发能力的企业,比较花费时间和金钱成本。第二种是找到第三方

3_创建Tab控件

1,新建MFC 对话框项目,为对话框添加Tab控件,选中Tab控件,新建控件变量m_tab_ctrl 2,为Tab控件添加tab项 m_tab_ctrl.InsertItem(0, L”000”),参数1,哪个位置;参数2,item的名称 3,为Tab控件添加监听事件, void C测试Dlg::OnTcnSelchangeTab1(NMHDR *pNMHDR, LRESUL

Linux C/C++ socket函数

目录 socket函数 函数原型 头文件 功能 返回值 参数 错误码 socket函数 函数原型 int socket(int domain, int type, int protocol); 头文件                 #include <sys/types.h>                 #include <sys/socket.h>