App啟動流程分析(上)
App啟動流程分析
一.概述流程
在LAUNCH介面,點選一個app的圖示之後,會呼叫startActivity來啟動對應的Activity。
通過Binder遠端通知AMS啟動新的Activity。
- AMS進行一系列的許可權判斷,建立ActivityRecord記錄資訊,Activity棧處理….等等一系列處理,最後會呼叫到startSpecificActivityLocked方法中。
- startSpecificActivityLocked方法中會進行判斷,在程序沒有啟動的情況下,會呼叫startProcessLocked=>startProcessLocked=>Process.start()來啟動一個程序。
- Process.start()是一個靜態方法,他作為客戶端會通過sockt與zygote進行通訊,Zygote作為服務端。Zygote通過JNI呼叫native方法fork一個它的子程序,並返回程序的pid。
- 呼叫zygoteConnection的handleChildProc方法。關閉socoket,進行一些程序的設定,預設未捕捉異常的處理方法、時區的設定、重置log的配置,binder執行緒池和執行緒建立….
- 通過反射來呼叫到ActivityThread的main方法,main方法中建立主執行緒Looper、並呼叫attach方法。通過Binder通訊呼叫AMS的attachApplicationLocked()方法,啟動主執行緒Looper迴圈。
- 跨程序呼叫ApplicationThread的bindApplication方法,通過Handler傳送訊息呼叫到ActivityThread的handleBindApplication方法,在這個方法中會完成建立Context的實現類ContextImpl物件、初始化Intrumentation物件、建立Application物件、裝載Provider、呼叫Application的onCreate方法。
- 呼叫到realStartActivityLocked,然後跨程序呼叫到applicationThread的scheduleLaunchActivity方法,scheduleLaunchActivity就會正真建立Activity。
二.具體流程分析
一 . 遠端呼叫AMS中StartActivity
1.1 StartActivity
在Android中,當我們啟動一個新的Activity或者service時,都是直接在Activity中呼叫StartActivity或者startService方法。這個方法最終會呼叫到startActivityForResult
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
//呼叫Instrumentation中的execStartActivity方法
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
//requestCode為-1
if (requestCode >= 0) {
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
其中:mMainThread的資料型別是ActivityThread,其中mMainThread.getApplicationThread()方法得到ApplicationThread;
1.2 execStartActivity
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
//如果阻塞,直接return
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.setAllowFds(false);
//獲得ActivityManagerProxy物件,呼叫startActivity
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
null, 0, token, target != null ? target.mEmbeddedID : null,
requestCode, false, false, null, null, false);
//檢查Activity是否啟動成功
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
}
其中ActivityManagerNative.getDefault()
會獲得ActivityManagerService
的本地代理物件ActivityManagerProxy
, 呼叫ActivityManagerProxy.startActivity
會通過Binder跨程序呼叫AMS中的startActivity
方法;
二 Binder遠端呼叫
2.1 ActivityManagerNative.getDefault().startActivity
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR);
int grantedMode = data.readInt();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
boolean onlyIfNeeded = data.readInt() != 0;
boolean debug = data.readInt() != 0;
String profileFile = data.readString();
ParcelFileDescriptor profileFd = data.readInt() != 0
? data.readFileDescriptor() : null;
boolean autoStopProfiler = data.readInt() != 0;
//遠端呼叫AMS中的startActivity
int result = startActivity(app, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);
reply.writeNoException();
reply.writeInt(result);
return true;
}
三 AMS中具體啟動流程
3.1 AMS.startActivity()
public final int startActivity(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
//直接呼叫了ActivityStack中的startActivityMayWait
return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler,
null, null);
}
3.2 ActivityStack.startActivityMayWait()
直接呼叫了ActivityStack中的方法
final int startActivityMayWait(IApplicationThread caller, int callingUid,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, String profileFile, ParcelFileDescriptor profileFd,
boolean autoStopProfiler, WaitResult outResult, Configuration config) {
...
intent = new Intent(intent);
// 根據傳入的Intent收集要啟動的目標Activity的資訊
ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
profileFile, profileFd, autoStopProfiler);
...
ActivityContainer container = (ActivityContainer)iContainer;
synchronized (mService) {
//見3.3小結
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified, null);
...
return res;
}
}
3.3 ActivityStack.startActivityLocked()
final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType,
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified, ActivityRecord[] outActivity) {
int err = START_SUCCESS;
//呼叫者程序記錄物件
ProcessRecord callerApp = null;
//判斷呼叫者本身程序的存在,否則記錄START_PERMISSION_DENIED,並在後面return
if (caller != null) {
callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
err = START_PERMISSION_DENIED;
}
}
if (err == START_SUCCESS) {
Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid "
+ (callerApp != null ? callerApp.pid : callingPid));
}
//呼叫者Activity的Activity資訊記錄物件
ActivityRecord sourceRecord = null;
//要啟動的Activity的Activity資訊記錄物件
ActivityRecord resultRecord = null;
if (resultTo != null) {
int index = indexOfTokenLocked(resultTo);
if (DEBUG_RESULTS) Slog.v(
TAG, "Will send result to " + resultTo + " (index " + index + ")");
if (index >= 0) {
//獲取呼叫者Activity的資訊記錄物件
sourceRecord = mHistory.get(index);
//requestCode等於-1則不進入
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
final int launchFlags = intent.getFlags();
/*處理標記位FLAG_ACTIVITY_FORWARD_RESULT。當有這個標記時,表示啟動Activity時使用的是startActivityForResult。*/
if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
&& sourceRecord != null) {
if (requestCode >= 0) {
return START_FORWARD_AND_REQUEST_CONFLICT;
}
resultRecord = sourceRecord.resultTo;
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(
sourceRecord, resultWho, requestCode);
}
}
//從Intent中無法找到相應的Component
if (err == START_SUCCESS && intent.getComponent() == null) {
err = START_INTENT_NOT_RESOLVED;
}
//從Intent中無法找到相應的ActivityInfo
if (err == START_SUCCESS && aInfo == null) {
err = START_CLASS_NOT_FOUND;
}
//檢查呼叫者是否有許可權來啟動指定的Activity
final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,callingUid, aInfo.applicationInfo.uid, aInfo.exported);
...
//建立要啟動的Activity的Activity資訊記錄物件
ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,intent, resolvedType, aInfo, mService.mConfiguration,resultRecord, resultWho, requestCode, componentSpecified);
...
//呼叫startActivityUncheckedLocked,見3.4小結
err = startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
mDismissKeyguardOnNextActivity = false;
mService.mWindowManager.dismissKeyguard();
}
return err;
}
主要是做許可權檢查,目標Activity資訊的記錄…等等
3.4 ActivityStack.startActivityUncheckedLocked
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
int grantedMode, boolean onlyIfNeeded, boolean doResume) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
//獲得Intent中的啟動標誌
int launchFlags = intent.getFlags();
//啟動模式及Intent標誌位處理
...
//見3.5小結
startActivityLocked(r, newTask, doResume, keepCurTransition);
return START_SUCCESS;
}
這個方法中主要涉及了一些列的啟動模式和Intent標誌的處理,最後呼叫了與3.3小結中引數不同的startActivityLocked方法。
3.5 ActivityStack.startActivityLocked()
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition) {
final int NH = mHistory.size();
int addPos = -1;
//判斷目標Activity是不是在新Task棧中啟動,即newTask變數為false
if (!newTask) {
// 如果不在新Task中系統,那麼找到目標Activity位於那個task中
...
}
//將Activity放在Task的最頂層,並在WMS註冊Token
...
if (doResume) {
//見3.6小結
resumeTopActivityLocked(null);
}
}
3.6 ActivityStack.resumeTopActivityLocked()
final boolean resumeTopActivityLocked(ActivityRecord prev) {
// 從mHistory中獲得ActivityStack最上面的有效的Activity
ActivityRecord next = topRunningActivityLocked(null);
final boolean userLeaving = mUserLeaving;
mUserLeaving = false;
//如果next為null,那麼我們就要啟動Launcher主介面。
if (next == null) {
// There are no more activities! Let's just start up the
// Launcher...
if (mMainStack) {
return mService.startHomeActivityLocked();
}
}
next.delayedResume = false;
//判斷當前執行的Activity是否是目標Activity,是的話就不要重複啟動了
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
mService.mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
return false;
}
...
//
mStoppingActivities.remove(next);
mGoingToSleepActivities.remove(next);
next.sleeping = false;
mWaitingVisibleActivities.remove(next);
if (mPausingActivity != null) {
if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
return false;
}
//當mPausingActivity不為null,說明目前正在pause前一個activity,我們需要等待操作結束,所以直接return
if (mResumedActivity != null) {
if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
startPausingLocked(userLeaving, false);
return true;
}
if (prev != null && prev != next) {
//next.nowVisible為false的話表示即將啟動的Activity是不可見的
if (!prev.waitingVisible && next != null && !next.nowVisible) {
prev.waitingVisible = true;
mWaitingVisibleActivities.add(prev);
if (DEBUG_SWITCH) Slog.v(
TAG, "Resuming top, waiting visible to hide: " + prev);
} else {
if (prev.finishing) {
mService.mWindowManager.setAppVisibility(prev.appToken, false);
} else {
...
}
}
}
...
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare close transition: prev=" + prev);
if (mNoAnimActivities.contains(prev)) {
mService.mWindowManager.prepareAppTransition(
WindowManagerPolicy.TRANSIT_NONE, false);
} else {
mService.mWindowManager.prepareAppTransition(prev.task == next.task? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
}
//通知WMS前一個顯示的Activity即將被隱藏
mService.mWindowManager.setAppWillBeHidden(prev.appToken);
//通知WMS目標Activity正在成為可見
mService.mWindowManager.setAppVisibility(prev.appToken, false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: prev=" + prev);
if (mNoAnimActivities.contains(next)) {
mService.mWindowManager.prepareAppTransition(
WindowManagerPolicy.TRANSIT_NONE, false);
} else {
mService.mWindowManager.prepareAppTransition(prev.task == next.task
? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
: WindowManagerPolicy.TRANSIT_TASK_OPEN, false);
}
}
if (false) {
mService.mWindowManager.setAppWillBeHidden(prev.appToken);
mService.mWindowManager.setAppVisibility(prev.appToken, false);
}
} else if (mHistory.size() > 1) {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: no previous");
if (mNoAnimActivities.contains(next)) {
mService.mWindowManager.prepareAppTransition(
WindowManagerPolicy.TRANSIT_NONE, false);
} else {
mService.mWindowManager.prepareAppTransition(
WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false);
}
}
//表示目標Activity所屬的程序中已有例項在執行
if (next.app != null && next.app.thread != null) {
//通知WMS目標Activity正在成為可見
mService.mWindowManager.setAppVisibility(next.appToken, true);
//跟新一系列的全域性變數
ActivityRecord lastResumedActivity = mResumedActivity;
ActivityState lastState = next.state;
mService.updateCpuStats();
//設定Activity狀態為resumed
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
if (mMainStack) {
mService.addRecentTaskLocked(next.task);
}
mService.updateLruProcessLocked(next.app, true, true);
updateLRUListLocked(next);
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
boolean updated = false;
if (mMainStack) {
synchronized (mService) {
Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
if (config != null) {
next.frozenBeforeDestroy = true;
}
updated = mService.updateConfigurationLocked(config, next, false, false);
}
}
if (!updated) {
ActivityRecord nextNext = topRunningActivityLocked(null);
if (nextNext != next) {
// Do over!
mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
}
if (mMainStack) {
mService.setFocusedActivityLocked(next);
}
ensureActivitiesVisibleLocked(null, 0);
mService.mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
return true;
}
try {
ArrayList a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
next.app.thread.scheduleSendResult(next.appToken, a);
}
}
if (next.newIntents != null) {
next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
}
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
System.identityHashCode(next),
next.task.taskId, next.shortComponentName);
next.sleeping = false;
showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
//通知目標執行緒resume指定的Activity
next.app.thread.scheduleResumeActivity(next.appToken,
mService.isNextTransitionForward());
checkReadyForSleepLocked();
} catch (Exception e) {
...
startSpecificActivityLocked(next, true, false);
return true;
}
...
} else {
//表明目標Activity在程序中沒有例項存在
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
mService.mWindowManager.setAppStartingWindow(
next.appToken, next.packageName, next.theme,
mService.compatibilityInfoForPackageLocked(
next.info.applicationInfo),
next.nonLocalizedLabel,
next.labelRes, next.icon, next.windowFlags,
null, true);
}
if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
}
//見目標4.1小節
startSpecificActivityLocked(next, true, true);
}
return true;
}
主要功能:
- 找不到需要resume的Activity,表示需要啟動Launcher主介面。
- 否則,需要執行startPausingLocked()來pause前一個Activity
- 與WMS通訊,告知需要準備隱藏前一個Activity,準備顯示其另一個Activity
- 當目標程序中存在目標Activity,則跟新一系列的全域性變數,resumeActivity;
- 否則進入startSpecificActivityLocked環節
三. AMS中的最後一步
4.1 ActivityStack.startSpecificActivityLocked
private final void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// 根據目標執行緒的processName,以及呼叫者的id(uid)來獲得目標程序的ProcessRecord物件,從名稱可以看出是程序的資訊記錄物件。
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
if (r.launchTime == 0) {
r.launchTime = SystemClock.uptimeMillis();
if (mInitialStartTime == 0) {
mInitialStartTime = r.launchTime;
}
} else if (mInitialStartTime == 0) {
mInitialStartTime = SystemClock.uptimeMillis();
}
//當目標程序存在時,進入這個if判斷
if (app != null && app.thread != null) {
try {
app.addPackage(r.info.packageName);
//呼叫realStartActivityLocked真正開始啟動目標Activity
realStartActivityLocked(r, app, andResume, checkConfig);
//啟動完成直接return
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
//程式碼執行到這裡,就表示目標程序不存在,具體見4.2小節
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false);
}
4.2 ProcessRecord.startProcessLocked()
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
// 根據目標執行緒的processName,以及呼叫者的id(uid)來獲得目標程序的ProcessRecord物件,從名稱可以看出是程序的資訊記錄物件。
ProcessRecord app = getProcessRecordLocked(processName, info.uid);
...
//獲得hostingNameStr字串
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
...
//見4.3小節
startProcessLocked(app, hostingType, hostingNameStr);
return (app.pid != 0) ? app : null;
}
4.3ProcessRecord.startProcessLocked()
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
...
try {
//獲得uid,gids值;
int uid = app.info.uid;
int[] gids = null;
try {
gids = mContext.getPackageManager().getPackageGids(
app.info.packageName);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
...
//見5.1小節
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags,
app.info.targetSdkVersion, null);
} catch (RuntimeException e) {
// XXX do better error recovery.
app.pid = 0;
Slog.e(TAG, "Failure starting process " + app.processName, e);
}
}
Process.start方法是一個靜態方法可以直接呼叫
五. Process中與Zygote程序的通訊
5.1 Process.start
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int targetSdkVersion,
String[] zygoteArgs) {
try {
//見5.2小節
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, targetSdkVersion, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
...
}
}
5.2 Process.startViaZygote
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int targetSdkVersion,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
//建立一個泛型為String的list容器,
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-init, --setuid=, --setgid=,
// and --setgroups= must go first
//在list容器中封裝一些必要字串資訊。
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
//processClass字串的值為android.app.ActivityThread
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
//見5.3小節
return zygoteSendArgsAndGetResult(argsForZygote);
}
}
該過程主要工作是生成argsForZygote
容器,儲存了程序的uid、gid、groups、target-sdk、nice-name等一系列的引數。
5.3 Process.zygoteSendArgsAndGetResult
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)throws ZygoteStartFailedEx {
//呼叫這個方法,在這個方法中會通過Socket喚醒Zytote程序,見5.4小節
openZygoteSocketIfNeeded();
//sZygoteWriter在openZygoteSocketIfNeeded方法中初始化;
try {
//通過Socket將args中記錄的資訊傳送給Zytote程序
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.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");
}
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
}
//flush刷出緩衝區資料
sZygoteWriter.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
//獲得Zygote程序Fork出的子程序,即欲建立的目標程序。
result.pid = sZygoteInputStream.readInt();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = sZygoteInputStream.readBoolean();
return result;
} catch (IOException ex) {
try {
if (sZygoteSocket != null) {
sZygoteSocket.close();
}
} catch (IOException ex2) {
// we're going to fail anyway
Log.e(LOG_TAG,"I/O exception on routine close", ex2);
}
sZygoteSocket = null;
throw new ZygoteStartFailedEx(ex);
}
}
在呼叫openZygoteSocketIfNeeded之後會建立與Zytote程序的Socket通道
5.3 Process.openZygoteSocketIfNeeded
private static void openZygoteSocketIfNeeded()
throws ZygoteStartFailedEx {
int retryCount;
if (sPreviousZygoteOpenFailed) {
retryCount = 0;
} else {
retryCount = 10;
}
for (int retry = 0; (sZygoteSocket == null) && (retry < (retryCount + 1)); retry++ ) {
if (retry > 0) {
try {
Log.i("Zygote", "Zygote not up yet, sleeping...");
Thread.sleep(ZYGOTE_RETRY_MILLIS);
} catch (InterruptedException ex) {
// should never happen
}
}
//建立Socket客戶端
try {
sZygoteSocket = new LocalSocket();
//呼叫connect方法,喚醒Zygote程序端
sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
LocalSocketAddress.Namespace.RESERVED));
sZygoteInputStream
= new DataInputStream(sZygoteSocket.getInputStream());
sZygoteWriter =
new BufferedWriter(newOutputStreamWriter(sZygoteSocket.getOutputStream()), 256);
sPreviousZygoteOpenFailed = false;
break;
} catch (IOException ex) {
if (sZygoteSocket != null) {
try {
sZygoteSocket.close();
} catch (IOException ex2) {
Log.e(LOG_TAG,"I/O exception on close after exception",
ex2);
}
}
sZygoteSocket = null;
}
}
if (sZygoteSocket == null) {
sPreviousZygoteOpenFailed = true;
throw new ZygoteStartFailedEx("connect failed");
}
}
這個方法的主要作用就是建立Socket,然後喚醒Zygote程序,並連線Zygote程序端。
六. Zygote程序fork子程序
Zygote程序是init程序fork的子程序,程序啟動之後呼叫ZygoteInit.main()方法,經過建立socket管道,預載入資源後,最後呼叫runSelectLoop()方法。
6.1 ZygoteInit.runSelectLoopMode
private static void runSelectLoopMode() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList();
ArrayList<ZygoteConnection> peers = new ArrayList();
FileDescriptor[] fdArray = new FileDescriptor[4];
//sServerSocket是socket通訊中的服務端
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
//迴圈一定次數進行gc
int index;
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}
try {
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
//index等於0,表示有客戶端連線Zygote程序,建立ZygoteConnection物件,見6.2小節
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
//index>0,則代表通過socket接收來自Client的資料,執行相應操作,見6.3小節
} else {
boolean done;
done = peers.get(index).runOnce();
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
- 客戶端通過openZygoteSocketIfNeeded()與zygote程序建立連線。zygote程序收到客戶端連線請求後執行accept();然後再建立ZygoteConnection物件,並新增到fds容器中;
- 建立連線之後,可以跟客戶端通訊,進入runOnce()方法來接收客戶端資料,並執行程序建立工作。
6.2 ZygoteInit.acceptCommandPeer
private static ZygoteConnection acceptCommandPeer() {
try {
return new ZygoteConnection(sServerSocket.accept());
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}
6.3 ZygoteConnection.runOnce
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
//讀取socket客戶端傳送過來的引數列表
try {
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
if (args == null) {
// EOF reached.
closeSocket();
return true;
}
/** the stderr of the most recent request, if avail */
PrintStream newStderr = null;
if (descriptors != null && descriptors.length >= 3) {
newStderr = new PrintStream(
new FileOutputStream(descriptors[2]));
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try {
//將Client傳送過來的引數列表通過Arguments解析
parsedArgs = new Arguments(args);
...
//見6.3小節
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids, parsedArgs.debugFlags, rlimits);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}
try {
if (pid == 0) {
//子程序中執行
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//見小節6.4
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
//不會到達此處,子程序預期會丟擲ZygoteInit.MethodAndArgsCaller或執行exec()
return true;
} else {
// 在父程序中執行,如果pid小於0表示fork失敗
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
6.3 Zygote.forkAndSpecialize
public static int forkAndSpecialize(int uid, int gid, int[] gids,
int debugFlags, int[][] rlimits) {
//完成一些fork前的初始化工作:停止Daemon子執行緒,完成GC堆的初始化
preFork();
//直接呼叫了一個native方法
int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits);
//fork新程序後,啟動Zygote的4個Daemon執行緒,java堆整理,引用佇列,以及析構執行緒。
postFork();
相關推薦
App啟動流程分析(上)
App啟動流程分析
一.概述流程
在LAUNCH介面,點選一個app的圖示之後,會呼叫startActivity來啟動對應的Activity。
通過Binder遠端通知AMS啟動新的Activity。
AMS進行一系列的許可權判斷,建立Activity
iOS作業系統-- App啟動流程分析與優化
背景知識:
mach-o檔案為基於Mach核心的作業系統的可執行檔案、目的碼或動態庫,是.out的代替,其提供了更強的擴充套件性並提升了符號表中資訊的訪問速度,
符號表,用於標記原始碼中包括識別符號、宣告資訊、行號、函式名稱等元素的具體資訊,比如說資料型別、作用域以及記憶體地址,iOS符號表在dS
深入淺出Android中的App啟動流程分析
App啟動是指使用者點選手機桌面的app對應的icon開始,所以我們需要明白幾點基礎知識:
1.桌面也是一個Activity叫Launcher.java
2.在桌面點選icon啟動app跟在app內部啟動另一個Activity是一樣的都是呼叫startAct
App啟動流程分析(下)
我們知道Java中一個能夠獨立執行的java程式的方法入口是main方法,它是被Jvm識別呼叫的。而在Android中一個應用的開始也可說是從ActivityThread的main方法開始的,然而不同的是他不是由Jvm呼叫的。
上一節我們講到在ZygoteIn
Android5 Zygote 與 SystemServer 啟動流程分析
進一步 null 正常的 rtb 這樣的 ket constant vml resp
Android5 Zygote 與 SystemServer 啟動流程分析
Android5 Zygote 與 SystemServer 啟動流程分析
前言
zy
開機啟動流程分析
boot 啟動流程 本節索引 在對系統啟動流程進行分析的時候,我想你一定是對系統有了一定的了解。系統的啟動目前來講大都為串行接力的方式來啟動。而所謂的並行方式的啟動方式也是某一個階段的並行。所以我按照系統啟動的順序來把文章連綴起來。 * BIOS階段 * BootLoader階段
kexec 內核快速啟動流程分析
-- 令行 並且 內存 tab 執行過程 family use -a 一、命令行
1. kexec -l $kpwd --append="$arg"
其中$kpwd =目標內核的路徑
$arg =傳給內核的參數,與/proc/cmdline一致時表示重啟現有內核
從0移植uboot (二) _啟動流程分析
title tco ret 沒有 返回 ips css location config
來源:Linux社區 作者:xiaojiang1025 : http://www.linuxidc.com/Linux/2017-02/141019.htm
經過
u-boot.2012.10——mini2440(二、啟動流程分析)
我們 分享 默認 從數據 中斷 改變 處理 mini2440 https 參考資料:https://blog.csdn.net/suiyuan19840208/article/details/7239949
1、第一階段功能
* 硬件設備初始化
* 加載u-boot
GEF入門實例_總結_04_Eclipse插件啟動流程分析
理解 viso inf targe get ica order workbench 註意 一、前言
本文承接上一節:GEF入門實例_總結_03_顯示菜單和工具欄
註意到app目錄下的6個類文件。
這6個文件對RCP應用程序而言非常重要,可能我們現在對這幾個文件的理
[Abp 源碼分析] 一、Abp 框架啟動流程分析
arch rep man job dsi 法則 依賴 gconf dep
Abp 不一定僅用於 Asp.Net Core 項目,他也可以在 Console 與 WinFrom 項目當中進行使用,所以關於啟動流程可以分為兩種,一種是 Asp.Net Core 項目的啟動流程
linux-2.6.22.6內核啟動流程分析之配置
linux 分享圖片 src image 比較 文件包含 子目錄 2.6 config 配置過程最終結果是生成.config文件,我們想要對配置的目的有很清楚的了解,必須先對.config文件進行分析。通過cd命令切換到linux-2.6.22.6內核目錄,輸入vi .co
Flink on Yarn模式啟動流程分析
cin XML images ont list action -i 多個 信息 此文已由作者嶽猛授權網易雲社區發布。歡迎訪問網易雲社區,了解更多網易技術產品運營經驗。Flink On Yarn 架構Paste_Image.png前提條件首先需要配置YARN_CONF_DIR
App啟動流程
目錄介紹
1.什麼是Zygote程序
1.1 簡單介紹
1.2 各個程序的先後順序
1.3 程序作用說明
2.Zygote程序的啟動流程
2.1 原始碼位置
2.2 ZygoteInit類的main方法
2.3 regist
Spark2.2.2原始碼解析: 3.啟動worker節點啟動流程分析
本文啟動worker節點啟動流程分析
啟動命令:
${SPARK_HOME}/sbin/start-slave.sh spark://sysadmindeMacBook-Pro.local:7077
檢視start-slave.sh
Android9.0 Activity啟動流程分析(二)
文章目錄
1、ActivityThread的main函式
2. AMS的attachApplication函式
2.1 Part-I
2.2 Part-II
2.2.1 ApplicationThread的bindApp
Android9.0 Activity啟動流程分析(一)
1、ActivityRecord、TaskRecord、ActivityStack和ActivityDisplay介紹
本篇文章是基於Android refs/tags/android-9.0.0_r8分支的程式碼進行分析的 在分析Activity啟動的原始碼之前先介紹一下Act
s5pv210 -uboot(三)SD卡啟動流程分析
https://blog.csdn.net/wangweijundeqq/article/details/78886155 --------------------- 本文來自 MrT_WANG 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net
Android 虛擬機器簡單介紹——ART、Dalvik、啟動流程分析
Android 虛擬機器方面的知識,我是通過《深入理解 Android 核心設計思想》來學習的,內容特別多(只有一章,但有 160 頁),但感覺和 Android 開發有些偏了,因此很多內容都沒有認真去看,比如 EFL 格式等,這裡只是選取了一些感覺比較重要的做
Linux核心啟動流程分析(一)
1. 依據arch/arm/kernel/vmlinux.lds 生成linux核心原始碼根目錄下的vmlinux,這個vmlinux屬於未壓縮,帶除錯資訊、符號表的最初的核心,大小約23MB;
命令:arm-linux-gnu-ld -o vmlinux -T a