Android 程序在系統中如何完成啓動

一段程序的調用都有它的程序入口,衆所周知Java程序的入口在main方法。作爲Android來說應用程序的啓動是通過 ActivityThread 類 來執行的。系統中對於該類的介紹如下:

該類是管理應用程序進程中主線程的執行,調度和執行活動,廣播以及活動管理者請求的其他操作。

當我打開App時,首先調用的是這個類中的main方法,也就是說這裏控制着程序的啓動。

ActivityThread#main

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        //初始化當前的可訪問環境,主要是系統內部的可存儲環境
        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        //step 1:
        Looper.prepareMainLooper();

        //step 2:
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        //初始化一個線程安全的handler對象
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        //執行消息隊列,不斷輪詢消息。
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

main方法中重要的操作:

step 1:
Looper.prepareMainLooper() :初始化當前的線程作爲一個looper,並且標記爲應用中的main looper。後面還跟着對應的loop(),在消息隊列中輪詢接收的消息。

step 2:
實例化當前ActivityThread對象,並且調用attach。繼續分析該方法中的調用。

ActivityThread#attach

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());

        //step 1: 將ActivityManagerService 和 ApplicationThread 關聯起來
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
        // Don't set application object here -- if the system crashes,
        // we can't display an alert, we just want to die die die.
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());
        try {
            mInstrumentation = new Instrumentation();
            ContextImpl context = ContextImpl.createAppContext(
                    this, getSystemContext().mPackageInfo);
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    // add dropbox logging to libcore
    DropBox.setReporter(new DropBoxReporter());

    ViewRootImpl.ConfigChangedCallback configChangedCallback
            = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // We need to apply this change to the resources immediately, because upon returning
            // the view hierarchy will be informed about it.
            if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                    null /* compat */)) {
                updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                        mResourcesManager.getConfiguration().getLocales());

                // This actually changed the resources! Tell everyone about it.
                if (mPendingConfiguration == null
                        || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
                    mPendingConfiguration = globalConfig;
                    sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                }
            }
        }
    };
    // 添加配置信息接口回調
    ViewRootImpl.addConfigCallback(configChangedCallback);
}

上面方法中傳入的參數爲false,所以執行的是if中的邏輯。這裏面主要的操作就是通過ActivityManager.getService() 返回了ActivityManagerService對象,然後調用attachApplication方法將ApplicationThread 對象關聯。下面我們繼續進入attachApplication 方法來分析。

ActivityManagerService#attachApplication

@Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

ActivityManagerService#attachApplicationLocked

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {

    // Find the application record that is being attached...  either via
    // the pid if we are running in multiple processes, or just pull the
    // next app record if we are emulating process with anonymous threads.

    // step 1: 記錄正在運行的進程的詳細信息
    ProcessRecord app;
    long startTime = SystemClock.uptimeMillis();
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }

    //未找到對應pid的進程信息時,殺死該進程或者退出該ApplicationThread
    if (app == null) {
        Slog.w(TAG, "No pending application record for pid " + pid
                + " (IApplicationThread " + thread + "); dropping process");
        EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
        if (pid > 0 && pid != MY_PID) {
            killProcessQuiet(pid);
            //TODO: killProcessGroup(app.info.uid, pid);
        } else {
            try {
                thread.scheduleExit();
            } catch (Exception e) {
                // Ignore exceptions.
            }
        }
        return false;
    }

    // If this application record is still attached to a previous
    // process, clean it up now.
    if (app.thread != null) {
        handleAppDiedLocked(app, true, true);
    }

    // Tell the process all about itself.

    if (DEBUG_ALL) Slog.v(
            TAG, "Binding process pid " + pid + " to record " + app);

    // 初始化 ProcessRecord 類中基本信息,來保存當前的一些狀態
    final String processName = app.processName;
    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }

    EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

    app.makeActive(thread, mProcessStats);
    app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
    app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    app.forcingToImportant = null;
    updateProcessForegroundLocked(app, false, false);
    app.hasShownUi = false;
    app.debugging = false;
    app.cached = false;
    app.killedByAm = false;
    app.killed = false;


    // We carefully use the same state that PackageManager uses for
    // filtering, since we use this flag to decide if we need to install
    // providers when user is unlocked later
    app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);

    mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;

    if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
        Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
        msg.obj = app;
        mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
    }

    checkTime(startTime, "attachApplicationLocked: before bindApplication");

    if (!normalMode) {
        Slog.i(TAG, "Launching preboot mode app: " + app);
    }

    if (DEBUG_ALL) Slog.v(
        TAG, "New app record " + app
        + " thread=" + thread.asBinder() + " pid=" + pid);
    try {
        int testMode = ApplicationThreadConstants.DEBUG_OFF;
        if (mDebugApp != null && mDebugApp.equals(processName)) {
            testMode = mWaitForDebugger
                ? ApplicationThreadConstants.DEBUG_WAIT
                : ApplicationThreadConstants.DEBUG_ON;
            app.debugging = true;
            if (mDebugTransient) {
                mDebugApp = mOrigDebugApp;
                mWaitForDebugger = mOrigWaitForDebugger;
            }
        }
        String profileFile = app.instr != null ? app.instr.mProfileFile : null;
        ParcelFileDescriptor profileFd = null;
        int samplingInterval = 0;
        boolean profileAutoStop = false;
        boolean profileStreamingOutput = false;
        if (mProfileApp != null && mProfileApp.equals(processName)) {
            mProfileProc = app;
            profileFile = mProfileFile;
            profileFd = mProfileFd;
            samplingInterval = mSamplingInterval;
            profileAutoStop = mAutoStopProfiler;
            profileStreamingOutput = mStreamingOutput;
        }
        boolean enableTrackAllocation = false;
        if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
            enableTrackAllocation = true;
            mTrackAllocationApp = null;
        }

        // If the app is being launched for restore or full backup, set it up specially
        boolean isRestrictedBackupMode = false;
        if (mBackupTarget != null && mBackupAppName.equals(processName)) {
            isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
                    && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
                            || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
                            || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
        }

        if (app.instr != null) {
            notifyPackageUse(app.instr.mClass.getPackageName(),
                             PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
        }
        if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
                + processName + " with config " + getGlobalConfiguration());
        ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
        app.compat = compatibilityInfoForPackageLocked(appInfo);
        if (profileFd != null) {
            profileFd = profileFd.dup();
        }
        ProfilerInfo profilerInfo = profileFile == null ? null
                : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop,
                                   profileStreamingOutput);

        // We deprecated Build.SERIAL and it is not accessible to
        // apps that target the v2 security sandbox. Since access to
        // the serial is now behind a permission we push down the value.
        String buildSerial = Build.UNKNOWN;
        if (appInfo.targetSandboxVersion != 2) {
            buildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
                    ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
                    .getSerial();
        }

        // Check if this is a secondary process that should be incorporated into some
        // currently active instrumentation.  (Note we do this AFTER all of the profiling
        // stuff above because profiling can currently happen only in the primary
        // instrumentation process.)
        if (mActiveInstrumentation.size() > 0 && app.instr == null) {
            for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--) {
                ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
                if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
                    if (aInstr.mTargetProcesses.length == 0) {
                        // This is the wildcard mode, where every process brought up for
                        // the target instrumentation should be included.
                        if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
                            app.instr = aInstr;
                            aInstr.mRunningProcesses.add(app);
                        }
                    } else {
                        for (String proc : aInstr.mTargetProcesses) {
                            if (proc.equals(app.processName)) {
                                app.instr = aInstr;
                                aInstr.mRunningProcesses.add(app);
                                break;
                            }
                        }
                    }
                }
            }
        }

        checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
        mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
        if (app.instr != null) {
            thread.bindApplication(processName, appInfo, providers,
                    app.instr.mClass,
                    profilerInfo, app.instr.mArguments,
                    app.instr.mWatcher,
                    app.instr.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial);
        } else {
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial);
        }

        checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
        updateLruProcessLocked(app, false, null);
        checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
    } catch (Exception e) {
        // todo: Yikes!  What should we do?  For now we will try to
        // start another process, but that could easily get us in
        // an infinite loop of restarting processes...
        Slog.wtf(TAG, "Exception thrown during bind of " + app, e);

        app.resetPackageList(mProcessStats);
        app.unlinkDeathRecipient();
        startProcessLocked(app, "bind fail", processName);
        return false;
    }

    // Remove this record from the list of starting applications.
    mPersistentStartingProcesses.remove(app);
    if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
            "Attach application locked removing on hold: " + app);
    mProcessesOnHold.remove(app);

    boolean badApp = false;
    boolean didSomething = false;

    // See if the top visible activity is waiting to run in this process...
    // step2 : 頂部可見的活動等待啓動
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }

    // Find any services that should be running in this process...
    if (!badApp) {
        try {
            didSomething |= mServices.attachApplicationLocked(app, processName);
            checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
            badApp = true;
        }
    }

    // Check if a next-broadcast receiver is in this process...
    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            didSomething |= sendPendingBroadcastsLocked(app);
            checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
        } catch (Exception e) {
            // If the app died trying to launch the receiver we declare it 'bad'
            Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
            badApp = true;
        }
    }

    // Check whether the next backup agent is in this process...
    if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
                "New app is backup target, launching agent for " + app);
        notifyPackageUse(mBackupTarget.appInfo.packageName,
                         PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
        try {
            thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
                    compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
                    mBackupTarget.backupMode);
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
            badApp = true;
        }
    }

    if (badApp) {
        app.kill("error during init", true);
        handleAppDiedLocked(app, false, true);
        return false;
    }

    if (!didSomething) {
        updateOomAdjLocked();
        checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
    }

    return true;
}

上面的方法中,首先使用了ProcessRecord記錄了進程中的一些信息,讓後將ProcessRecord 與 ActivityStackSupervisor 關聯起來,通過ActivityStackSupervisor可以運行所有的活動棧。

ActivityStackSupervisor#attachApplicationLocked

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (!isFocusedStack(stack)) {
                continue;
            }
            //step 1:檢查當前活動是否應該被顯示
            ActivityRecord hr = stack.topRunningActivityLocked();
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        //step 2:
                        if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                              + hr.intent.getComponent().flattenToShortString(), e);
                        throw e;
                    }
                }
            }
        }
    }
    if (!didSomething) {
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    }
    return didSomething;
}

遍歷活動棧後,首先執行方法topRunningActivityLocked,然後找出當前線程匹配的活動執行realStartActivityLocked方法。

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {

    if (!allPausedActivitiesComplete()) {
        // While there are activities pausing we skipping starting any new activities until
        // pauses are complete. NOTE: that we also do this for activities that are starting in
        // the paused state because they will first be resumed then paused on the client side.
        if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
                "realStartActivityLocked: Skipping start of r=" + r
                + " some activities pausing...");
        return false;
    }

    r.startFreezingScreenLocked(app, 0);
    if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */, true /* isTop */)) {
        // We only set the visibility to true if the activity is allowed to be visible based on
        // keyguard state. This avoids setting this into motion in window manager that is later
        // cancelled due to later calls to ensure visible activities that set visibility back to
        // false.
        r.setVisibility(true);
    }

    // schedule launch ticks to collect information about slow apps.
    r.startLaunchTickingLocked();

    // Have the window manager re-evaluate the orientation of the screen based on the new
    // activity order.  Note that as a result of this, it can call back into the activity
    // manager with a new orientation.  We don't care about that, because the activity is not
    // currently running so we are just restarting it anyway.
    if (checkConfig) {
        final int displayId = r.getDisplayId();
        final Configuration config = mWindowManager.updateOrientationFromAppTokens(
                getDisplayOverrideConfiguration(displayId),
                r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId);
        // Deferring resume here because we're going to launch new activity shortly.
        // We don't want to perform a redundant launch of the same record while ensuring
        // configurations and trying to resume top activity of focused stack.
        mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */,
                displayId);
    }

    if (mKeyguardController.isKeyguardLocked()) {
        r.notifyUnknownVisibilityLaunched();
    }
    final int applicationInfoUid =
            (r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
    if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) {
        Slog.wtf(TAG,
                "User ID for activity changing for " + r
                        + " appInfo.uid=" + r.appInfo.uid
                        + " info.ai.uid=" + applicationInfoUid
                        + " old=" + r.app + " new=" + app);
    }

    r.app = app;
    app.waitingToKill = null;
    r.launchCount++;
    r.lastLaunchTime = SystemClock.uptimeMillis();

    if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);

    int idx = app.activities.indexOf(r);
    if (idx < 0) {
        app.activities.add(r);
    }
    mService.updateLruProcessLocked(app, true, null);
    mService.updateOomAdjLocked();

    final TaskRecord task = r.getTask();
    if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
            task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
        setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
    }

    final ActivityStack stack = task.getStack();
    try {
        if (app.thread == null) {
            throw new RemoteException();
        }
        List<ResultInfo> results = null;
        List<ReferrerIntent> newIntents = null;
        if (andResume) {
            // We don't need to deliver new intents and/or set results if activity is going
            // to pause immediately after launch.
            results = r.results;
            newIntents = r.newIntents;
        }
        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                "Launching: " + r + " icicle=" + r.icicle + " with results=" + results
                + " newIntents=" + newIntents + " andResume=" + andResume);
        EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId,
                System.identityHashCode(r), task.taskId, r.shortComponentName);
        if (r.isHomeActivity()) {
            // Home process is the root process of the task.
            mService.mHomeProcess = task.mActivities.get(0).app;
        }
        mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
        r.sleeping = false;
        r.forceNewConfig = false;
        mService.showUnsupportedZoomDialogIfNeededLocked(r);
        mService.showAskCompatModeDialogLocked(r);
        r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
        ProfilerInfo profilerInfo = null;
        if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
            if (mService.mProfileProc == null || mService.mProfileProc == app) {
                mService.mProfileProc = app;
                final String profileFile = mService.mProfileFile;
                if (profileFile != null) {
                    ParcelFileDescriptor profileFd = mService.mProfileFd;
                    if (profileFd != null) {
                        try {
                            profileFd = profileFd.dup();
                        } catch (IOException e) {
                            if (profileFd != null) {
                                try {
                                    profileFd.close();
                                } catch (IOException o) {
                                }
                                profileFd = null;
                            }
                        }
                    }

                    profilerInfo = new ProfilerInfo(profileFile, profileFd,
                            mService.mSamplingInterval, mService.mAutoStopProfiler,
                            mService.mStreamingOutput);
                }
            }
        }

        app.hasShownUi = true;
        app.pendingUiClean = true;
        app.forceProcessStateUpTo(mService.mTopProcessState);
        // Because we could be starting an Activity in the system process this may not go across
        // a Binder interface which would create a new Configuration. Consequently we have to
        // always create a new Configuration here.

        final MergedConfiguration mergedConfiguration = new MergedConfiguration(
                mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
        r.setLastReportedConfiguration(mergedConfiguration);

        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info,
                // TODO: Have this take the merged configuration instead of separate global and
                // override configs.
                mergedConfiguration.getGlobalConfiguration(),
                mergedConfiguration.getOverrideConfiguration(), r.compat,
                r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                r.persistentState, results, newIntents, !andResume,
                mService.isNextTransitionForward(), profilerInfo);

        if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
            // This may be a heavy-weight process!  Note that the package
            // manager will ensure that only activity can run in the main
            // process of the .apk, which is the only thing that will be
            // considered heavy-weight.
            if (app.processName.equals(app.info.packageName)) {
                if (mService.mHeavyWeightProcess != null
                        && mService.mHeavyWeightProcess != app) {
                    Slog.w(TAG, "Starting new heavy weight process " + app
                            + " when already running "
                            + mService.mHeavyWeightProcess);
                }
                mService.mHeavyWeightProcess = app;
                Message msg = mService.mHandler.obtainMessage(
                        ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
                msg.obj = r;
                mService.mHandler.sendMessage(msg);
            }
        }

    } catch (RemoteException e) {
        if (r.launchFailed) {
            // This is the second time we failed -- finish activity
            // and give up.
            Slog.e(TAG, "Second failure launching "
                  + r.intent.getComponent().flattenToShortString()
                  + ", giving up", e);
            mService.appDiedLocked(app);
            stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
                    "2nd-crash", false);
            return false;
        }

        // This is the first time we failed -- restart process and
        // retry.
        r.launchFailed = true;
        app.activities.remove(r);
        throw e;
    }

    r.launchFailed = false;
    if (stack.updateLRUListLocked(r)) {
        Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
    }

    if (andResume) {
        // As part of the process of launching, ActivityThread also performs
        // a resume.
        stack.minimalResumeActivityLocked(r);
    } else {
        // This activity is not starting in the resumed state... which should look like we asked
        // it to pause+stop (but remain visible), and it has done so and reported back the
        // current icicle and other state.
        if (DEBUG_STATES) Slog.v(TAG_STATES,
                "Moving to PAUSED: " + r + " (starting in paused state)");
        r.state = PAUSED;
    }

    // Launch the new version setup screen if needed.  We do this -after-
    // launching the initial activity (that is, home), so that it can have
    // a chance to initialize itself while in the background, making the
    // switch back to it faster and look better.
    if (isFocusedStack(stack)) {
        mService.startSetupActivityLocked();
    }

    // Update any services we are bound to that might care about whether
    // their client may have activities.
    if (r.app != null) {
        mService.mServices.updateServiceConnectionActivitiesLocked(r.app);
    }

    return true;
}

通過這個方法中完成了一些啓動Activity的準備工作,然後調用scheduleLaunchActivity方法,從上面我們可以知道這裏調用的是ApplicationThread中的方法:

ActivityThread.ApplicationThread#scheduleLaunchActivity

@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
        int procState, Bundle state, PersistableBundle persistentState,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

    updateProcessState(procState, false);

    ActivityClientRecord r = new ActivityClientRecord();

    r.token = token;
    r.ident = ident;
    r.intent = intent;
    r.referrer = referrer;
    r.voiceInteractor = voiceInteractor;
    r.activityInfo = info;
    r.compatInfo = compatInfo;
    r.state = state;
    r.persistentState = persistentState;

    r.pendingResults = pendingResults;
    r.pendingIntents = pendingNewIntents;

    r.startsNotResumed = notResumed;
    r.isForward = isForward;

    r.profilerInfo = profilerInfo;

    r.overrideConfig = overrideConfig;
    updatePendingConfiguration(curConfig);

    sendMessage(H.LAUNCH_ACTIVITY, r);
}

在這裏我們可以看到調用的是Handler的消息通信機制,當Activity狀態改變時,都會有對應的一個消息發送出去。而且我們還看到ApplicationThread類中包含了許多不同的scheduleXXX 類的方法,這些方法代表了不同啓動狀態,每個狀態的改變都通過它來發送給Handler進行處理。

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

            r.packageInfo = getPackageInfoNoCheck(
                    r.activityInfo.applicationInfo, r.compatInfo);
            handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;
        case RELAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
            ActivityClientRecord r = (ActivityClientRecord)msg.obj;
            handleRelaunchActivity(r);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;
        case PAUSE_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
            SomeArgs args = (SomeArgs) msg.obj;
            handlePauseActivity((IBinder) args.arg1, false,
                    (args.argi1 & USER_LEAVING) != 0, args.argi2,
                    (args.argi1 & DONT_REPORT) != 0, args.argi3);
            maybeSnapshot();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;
        case PAUSE_ACTIVITY_FINISHING: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
            SomeArgs args = (SomeArgs) msg.obj;
            handlePauseActivity((IBinder) args.arg1, true, (args.argi1 & USER_LEAVING) != 0,
                    args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;

        ....

由此我們可以得出一個結論,Application運行過程中,對於Activity的操作狀態轉變,都是通過Handler消息機制來完成的。而這個消息隊列就是在ActivityThread中main方法裏面輪詢的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章