1. 程式人生 > >Android6.0之AMS通過socket與zygote通訊建立app程序

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所在的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堆整理,引用佇列,以及析構執行緒(前面暫停了)。