android Activity启动流程(5)

/ android / 没有评论 / 941浏览

用到的代码文件

frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/java/android/app/ApplicationThreadNative.java
frameworks/base/core/java/android/app/ActivityManagerNative.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

代码执行流程图

android activity 查看原图

模块编译

mm frameworks/base/services/ -> system/framework/services.jar
mm frameworks/base/ -> system/framework/framework.jar

单编一个模块用mm,将一个模板及其相关依赖全编用mmma。
如果你的整个android rom代码全编译过一次,推荐用mm,因为能节约一大部分时间!

android activity启动流程

下面的代码是以android N(api 24)为基础。

承接上文android Activity启动流程(4)

Zygote通过socket通信的方式让Zygote进程fork除了一个新的进程,并根据我们刚刚传递的”android.app.ActivityThread”字符串,反射出该对象并执行ActivityThread的main方法。这样我们所要启动的应用进程这时候其实已经启动了,但是还没有执行相应的初始化操作。

就在新的进程中Java反射开始执行ActivityThread类中main()方法。

public static void main(String[] args) {
    log("method called main() start a new process");
    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>");

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    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");
}

接下来进入ActivityThread类中attach()方法。

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) { // -> true
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        log("mgr : "+mgr.getClass().getName());// mgr : android.app.ActivityManagerProxy
        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.addConfigCallback(new ComponentCallbacks2() {
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            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(newConfig, null)) {
                    updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                            mResourcesManager.getConfiguration().getLocales());

                    // This actually changed the resources!  Tell
                    // everyone about it.
                    if (mPendingConfiguration == null ||
                            mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                        mPendingConfiguration = newConfig;

                        sendMessage(H.CONFIGURATION_CHANGED, newConfig);
                    }
                }
            }
        }
        @Override
        public void onLowMemory() {
        }
        @Override
        public void onTrimMemory(int level) {
        }
    });
}

进入ActivityManagerProxy类中的attachApplication()方法。

public void attachApplication(IApplicationThread app) throws RemoteException
{
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(app.asBinder());
    mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
    reply.readException();
    data.recycle();
    reply.recycle();
}

这里通过Binder通信的方式发送消息,而接收端就是我们的ActivityManagerService。
AMS调用其内部的attachApplication()方法。

@Override
public final void attachApplication(IApplicationThread thread) {
    log("thread : "+thread.getClass().getName()); //android.app.ApplicationThreadProxy
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        log("callingPid : "+callingPid); //3941
        log("origId : "+origId); //43400644530021
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

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.
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) { // -> true
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }

    log("app : "+app);//ProcessRecord{241c461 3941:com.jrdcom.filemanager/u0a105}

    if (app == null) { // -> false
        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) {
            Process.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) { // -> false
        handleAppDiedLocked(app, true, true);
    }

    ......(省略一大段代码,做了一个进程ProcessRecord等相关初始化工作)

    // See if the top visible activity is waiting to run in this process...
    if (normalMode) { // -> true
        try {
            /**
              * 进入这里
              */
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    log("badApp : "+badApp);  //false
    // Find any services that should be running in this process...
    if (!badApp) {
        try {
            didSomething |= mServices.attachApplicationLocked(app, processName);
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
            badApp = true;
        }
    }

    ......(一些检查工作)

    return true;
}

接下来进入ActivityStackSupervisor中attachApplicationLocked()方法。

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    log("method called attachApplicationLocked()");
    log("app : "+app); //ProcessRecord{40ac255 3766:com.jrdcom.filemanager/u0a105}
    final String processName = app.processName;
    boolean didSomething = false;
    log("mActivityDisplays.size() : "+mActivityDisplays.size()); // 1
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        log("stacks.size() : "+stacks.size()); //2
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            log("stack : "+stack);//stack : ActivityStack{58e4ec8 stackId=1, 1 tasks}
            if (!isFocusedStack(stack)) {
                continue;
            }
            ActivityRecord hr = stack.topRunningActivityLocked();
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        log("hr : "+hr);//ActivityRecord{5e0f9b0 u0 com.jrdcom.filemanager/.activity.FileBrowserActivity t16}
                        log("real start activity locked");
                        /*
                          * 正儿八经的开始start activity
                          */
                        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;
}

接下来进入realStartActivityLocked()方法。

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
    log("method called realStartActivityLocked()");
    if (!allPausedActivitiesComplete()) { //-> false
        // 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;
    }

    if (andResume) { // -> true
        r.startFreezingScreenLocked(app, 0);
        mWindowManager.setAppVisibility(r.appToken, 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) { // -> true
        Configuration config = mWindowManager.updateOrientationFromAppTokens(
                mService.mConfiguration,
                r.mayFreezeScreenLocked(app) ? r.appToken : null);
        log("config : "+config); //config is null
        mService.updateConfigurationLocked(config, r, false);
    }

    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);
    log("idx : "+idx); // -1
    if (idx < 0) { // -> true
        app.activities.add(r);
    }
    mService.updateLruProcessLocked(app, true, null);
    mService.updateOomAdjLocked();

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

    final ActivityStack stack = task.stack;
    try {
        if (app.thread == null) {
            throw new RemoteException();
        }
        List<ResultInfo> results = null;
        List<ReferrerIntent> newIntents = null;
        if (andResume) {
            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);
        if (andResume) {
            EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
                    r.userId, System.identityHashCode(r),
                    task.taskId, r.shortComponentName);
        }
        if (r.isHomeActivity()) { // -> false
            // 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;
        log("mService.mProfileApp : "+mService.mProfileApp); // is null
        if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) { // -> false
            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);
                }
            }
        }

        if (andResume) {
            app.hasShownUi = true;
            app.pendingUiClean = true;
        }
        app.forceProcessStateUpTo(mService.mTopProcessState);
        log("app.thread : "+app.thread.getClass().getName()); //android.app.ApplicationThreadProxy
        /**
          * 进入这里
          */
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                new Configuration(task.mOverrideConfig), 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) { // -> false
            // 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.
        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) { // -> true
        // 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)) { // -> true
        mService.startSetupActivityLocked();
    }

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

    return true;
}

进入ApplicationThreadProxy类中的scheduleLaunchActivity()方法。
ApplicationThreadProxy是定义在ApplicationThreadNative中的内部类。

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) throws RemoteException {
    Parcel data = Parcel.obtain();
    data.writeInterfaceToken(IApplicationThread.descriptor);
    intent.writeToParcel(data, 0);
    data.writeStrongBinder(token);
    data.writeInt(ident);
    info.writeToParcel(data, 0);
    curConfig.writeToParcel(data, 0);
    if (overrideConfig != null) {
        data.writeInt(1);
        overrideConfig.writeToParcel(data, 0);
    } else {
        data.writeInt(0);
    }
    compatInfo.writeToParcel(data, 0);
    data.writeString(referrer);
    data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
    data.writeInt(procState);
    data.writeBundle(state);
    data.writePersistableBundle(persistentState);
    data.writeTypedList(pendingResults);
    data.writeTypedList(pendingNewIntents);
    data.writeInt(notResumed ? 1 : 0);
    data.writeInt(isForward ? 1 : 0);
    if (profilerInfo != null) {
        data.writeInt(1);
        profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    } else {
        data.writeInt(0);
    }
    mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
            IBinder.FLAG_ONEWAY);
    data.recycle();
}

可以看见又通过Binder通信了.....