Android 程序在系统中如何完成启动

Posted yuminfeng728

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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方法里面轮询的。

以上是关于Android 程序在系统中如何完成启动的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Android 中的单个应用程序启动自助服务终端应用程序

Linux系统启动流程

Android 源码分析 Launcher 启动

如何在cygwin中启动X窗口

如何在android APP中设置系统语言

在 Android 中启动完成后自动启动应用程序