Android6.0之AMS啓動app中篇之創建app進程

前面分析到了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所在的task
    for (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  task
             resetTaskIfNeededLocked(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,那麼設置爲當前處於前臺的ActivityStack
      if (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的話,那就直接返回false
    if (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銷燬了,移動到home
      final 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的onResume
                next.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,那麼這麼這裏也設置爲true
           r.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;//傳入的兩者相等,所以爲fasle
    uid = _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,// null
            String entryPoint,// null
            String[] 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{
      // 得到pms
      final 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來說,設置爲系統的主abi
  if (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,所以爲true
  boolean 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.ActivityThread
                              final String niceName,//進程的名字
                              int uid, int gid, int[] gids,// 進程uid gid,權限相關
                              int debugFlags, // app在清單文件中設置的進程相關標記 ,以及系統設置的進程標記,例如是否讓VM執行checkjni等
                              int mountExternal,// 外部存儲相關
                              int targetSdkVersion,// app中指定的targetSdkVersion
                              String 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);
      // 傳入的爲null
     if (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();
            }
            // 將信息發送給zygote
            writer.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肯定大於0
                ZygoteConnection 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文件時,需要一個bridge
    bool 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) {
          .......................
        }
    }
    //設置設置group
    SetGids(env, javaGids);
    //設置資源limit
    SetRLimits(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爲0
    SetCapabilities(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爲default
    if (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);
    //設置新進程的主線程id
    thread->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時,則創建JIT
    CreateJit();
  }
  //設置信號處理函數
  StartSignalCatcher();
  //啓動JDWP線程,當命令debuger的flags指定"suspend=y"時,則暫停runtime
  Dbg::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.main
        RuntimeInit.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() {
        @Override
        public 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.75
      VMRuntime.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 exit
          return;
      }

      // Remaining arguments are passed to the start class's static main
      invokeStaticMain(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爲null
        cl = 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的進程算是創建完畢了,進程執行的第一個方法也找到是誰了.

發佈了14 篇原創文章 · 獲贊 26 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章