1. 程式人生 > >App啟動流程分析(上)

App啟動流程分析(上)

App啟動流程分析

一.概述流程

  1. 在LAUNCH介面,點選一個app的圖示之後,會呼叫startActivity來啟動對應的Activity。

  2. 通過Binder遠端通知AMS啟動新的Activity。

  3. AMS進行一系列的許可權判斷,建立ActivityRecord記錄資訊,Activity棧處理….等等一系列處理,最後會呼叫到startSpecificActivityLocked方法中。
  4. startSpecificActivityLocked方法中會進行判斷,在程序沒有啟動的情況下,會呼叫startProcessLocked=>startProcessLocked=>Process.start()來啟動一個程序。
  5. Process.start()是一個靜態方法,他作為客戶端會通過sockt與zygote進行通訊,Zygote作為服務端。Zygote通過JNI呼叫native方法fork一個它的子程序,並返回程序的pid。
  6. 呼叫zygoteConnection的handleChildProc方法。關閉socoket,進行一些程序的設定,預設未捕捉異常的處理方法、時區的設定、重置log的配置,binder執行緒池和執行緒建立….
  7. 通過反射來呼叫到ActivityThread的main方法,main方法中建立主執行緒Looper、並呼叫attach方法。通過Binder通訊呼叫AMS的attachApplicationLocked()方法,啟動主執行緒Looper迴圈。
  8. 跨程序呼叫ApplicationThread的bindApplication方法,通過Handler傳送訊息呼叫到ActivityThread的handleBindApplication方法,在這個方法中會完成建立Context的實現類ContextImpl物件、初始化Intrumentation物件、建立Application物件、裝載Provider、呼叫Application的onCreate方法。
  9. 呼叫到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