android学习--Activity及应用启动过程

来源:互联网 发布:红包埋雷软件 编辑:程序博客网 时间:2024/05/17 08:11

  Activity是android 的四大组件之一,应用场景是比较常见的,从前面的AMS我们已经了解android 管理activity的服务启动。这次重点分析一下activity的启动过程。

我们先从startActivity开始分析:

    public void startActivity(Intent intent, Bundle options) {        if (options != null) {            startActivityForResult(intent, -1, options);        } else {            // Note we want to go through this call for compatibility with            // applications that may have overridden the method.            startActivityForResult(intent, -1);        }    }
然后直接到startActivityForResult里面通过Instrumentation来启动一个activity,我们先来了解一下什么是Instrumentation。从字面意义上面理解为测量,我们可以当它是一个工具类。每个应用都有一个Instrumentation类,任务activity都有这个对象的应用,它就像系统和应用之间加了一道“墙”,用来监测系统和应用之间的交互。

 Instrumentation.ActivityResult ar =                mInstrumentation.execStartActivity(                    this, mMainThread.getApplicationThread(), mToken, this,<span style="font-size:18px;">                    intent, requestCode, options);</span>
直接看execStartActivity函数:

IApplicationThread whoThread = (IApplicationThread) contextThread;        if (mActivityMonitors != null) {            synchronized (mSync) {                final int N = mActivityMonitors.size();                for (int i=0; i<N; i++) {                    final ActivityMonitor am = mActivityMonitors.get(i);                    if (am.match(who, null, intent)) {                        am.mHits++;                        if (am.isBlocking()) {                            return requestCode >= 0 ? am.getResult() : null;                        }                        break;                    }                }            }        }        try {            intent.migrateExtraStreamToClipData();            intent.prepareToLeaveProcess();            int result = ActivityManagerNative.getDefault()                .startActivity(whoThread, who.getBasePackageName(), intent,                        intent.resolveTypeIfNeeded(who.getContentResolver()),                        token, target != null ? target.mEmbeddedID : null,                        requestCode, 0, null, null, options);            checkStartActivityResult(result, intent);        } catch (RemoteException e) {        }
1.mActivityMonitors保存已经启动过的activity,相关做一个记录。

2.调用ActivityManagerNative启动一个activity,这里有一个相当重要的变量:whoThread = (IApplicationThread) contextThread; 我们先来理解一下什么是IApplicationThread? AMS要管理应用过程,本身就是一个跨进程的过程,因为AMS是在系统进程,而应用是在应用进程,所以这种跨进程的操作是通过binder机制来实现的。那么是服务端和客户端?这里的两个都是服务端,也都是客户端,对于AMS操作应用进程,应用进程是服务端,AMS是客户端,它们是通过IApplicationThread来实现。那个应用进程想调用AMS时,AMS又成了服务端,应用进程就是客户端。

所以这里的whoThread是指启动activity的进程方,IApplicationThread的实现是ActivityThread实现的。

ActivityManagerNative.getDefault()拿到服务端的代理对象ActivityManagerProxy。然后再打包通过mRemote发送给远程服务器

mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
而远程服务端的实现就是AMS:

 public final int startActivity(IApplicationThread caller, String callingPackage,            Intent intent, String resolvedType, IBinder resultTo,            String resultWho, int requestCode, int startFlags,            String profileFile, ParcelFileDescriptor profileFd, Bundle options) {        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,                resultWho, requestCode,                startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());    }
最终会进入ActivityStackSupervisor的startActivityMayWait方法:

...............        // Collect information about the target of the Intent.        ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,                profileFile, profileFd, userId);        synchronized (mService) {            int callingPid;            if (callingUid >= 0) {                callingPid = -1;            } else if (caller == null) {                callingPid = Binder.getCallingPid();                callingUid = Binder.getCallingUid();            } else {                callingPid = callingUid = -1;            }            ..........            int res = startActivityLocked(caller, intent, resolvedType,                    aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,                    callingPackage, startFlags, options, componentSpecified, null);            ............            Binder.restoreCallingIdentity(origId);            if (outResult != null) {                outResult.result = res;                if (res == ActivityManager.START_SUCCESS) {                    mWaitingActivityLaunched.add(outResult);                    do {                        try {                            mService.wait();                        } catch (InterruptedException e) {                        }                    } while (!outResult.timeout && outResult.who == null);                } else if (res == ActivityManager.START_TASK_TO_FRONT) {                  .......            }            return res;        }
1.根据intent对象,调用PMS查询相关的activityInfo对象。resolveActivity 返回查询到持activityInfo对象。

 ActivityInfo aInfo;        try {            ResolveInfo rInfo =                AppGlobals.getPackageManager().resolveIntent(                        intent, resolvedType,                        PackageManager.MATCH_DEFAULT_ONLY                                    | ActivityManagerService.STOCK_PM_FLAGS, userId);            aInfo = rInfo != null ? rInfo.activityInfo : null;        } catch (RemoteException e) {            aInfo = null;        }        if (aInfo != null) {            // Store the found target back into the intent, because now that            // we have it we never want to do this again.  For example, if the            // user navigates back to this point in the history, we should            // always restart the exact same activity.            intent.setComponent(new ComponentName(                    aInfo.applicationInfo.packageName, aInfo.name));

2.调用startActivityLocked(caller, intent, resolvedType,
                    aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
                    callingPackage, startFlags, options, componentSpecified, null);启动Activity。

3.如果有返回值:AMS进入阻塞状态。


我们接着看startActivityLocked方法:主要功能是做一下检测,比如Caller进程是否还存在,还有是否有权限,但这并不会影响流程。最终到startActivityUncheckedLocked 方法:方法比较长,主要功能是关于launchemode的处理,启动模式的处理。

if (sourceRecord == null) {            // This activity is not being started from another...  in this            // case we -always- start a new task.            if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {                Slog.w(TAG, "startActivity called from non-Activity context; forcing " +                        "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;            }        } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {            // The original activity who is starting us is running as a single            // instance...  this new activity it is starting must go on its            // own task.            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {            // The activity being started is a single instance...  it always            // gets launched into its own task.            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;        }
如果启动模式为LAUNCH_SINGLE_TASK 或者LAUNCH_SINGLE_INSTANCE 证明要启动新的栈.

后面还是有复杂的处理,这里不是分析的重点。获得目标栈之后,再调用 targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);来启动activity.

final void startActivityLocked(ActivityRecord r, boolean newTask,            boolean doResume, boolean keepCurTransition, Bundle options) {        TaskRecord rTask = r.task;        .....        TaskRecord task = null;        if (!newTask) {            // If starting in an existing task, find where that is...            boolean startIt = true;            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {                task = mTaskHistory.get(taskNdx);                if (task == r.task) {                    // Here it is!  Now, if this is not yet visible to the                    // user, then just add it without starting; it will                    // get started when the user navigates back to it.                    if (!startIt) {                        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "                                + task, new RuntimeException("here").fillInStackTrace());                        task.addActivityToTop(r);                        r.putInHistory();                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,                                r.userId, r.info.configChanges);                        if (VALIDATE_TOKENS) {                            validateAppTokensLocked();                        }                        ActivityOptions.abort(options);                        return;                    }                    break;                } else if (task.numFullscreen > 0) {                    startIt = false;                }            }        }        ...............        if (doResume) {            mStackSupervisor.resumeTopActivitiesLocked();        }    }
1.把当前ActivityRecord添加到栈中。

2.然后resume当前栈的activity。

我们再来看一下resumeTopActivityLocked方法,这里假设要启动的activity的进程没有启动。就会执行:mStackSupervisor.startSpecificActivityLocked(next, true, true);方法。

void startSpecificActivityLocked(ActivityRecord r,            boolean andResume, boolean checkConfig) {        // Is this activity's application already running?        ProcessRecord app = mService.getProcessRecordLocked(r.processName,                r.info.applicationInfo.uid, true);        r.task.stack.setLaunchTime(r);        if (app != null && app.thread != null) {            try {                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0                        || !"android".equals(r.info.packageName)) {                    // Don't add this if it is a platform component that is marked                    // to run in multiple processes, because this is actually                    // part of the framework so doesn't make sense to track as a                    // separate apk in the process.                    app.addPackage(r.info.packageName, mService.mProcessStats);                }                realStartActivityLocked(r, app, andResume, checkConfig);                return;            } catch (RemoteException e) {                Slog.w(TAG, "Exception when starting activity "                        + r.intent.getComponent().flattenToShortString(), e);            }            // If a dead object exception was thrown -- fall through to            // restart the application.        }        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,                "activity", r.intent.getComponent(), false, false, true);    }
获取当前进程的记录app,如果app不为空,证明进程已经起来。如果为空,则目标进程还没有启动。

调用startProcessLocked启动目标进程。

   final ProcessRecord startProcessLocked(String processName,            ApplicationInfo info, boolean knownToBeDead, int intentFlags,            String hostingType, ComponentName hostingName, boolean allowWhileBooting,            boolean isolated, boolean keepIfLarge) {        ProcessRecord app;        if (!isolated) {            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);        } else {            // If this is an isolated process, it can't re-use an existing process.            app = null;        }        ................        if (app == null) {            app = newProcessRecordLocked(info, processName, isolated);            if (app == null) {                Slog.w(TAG, "Failed making new process record for "                        + processName + "/" + info.uid + " isolated=" + isolated);                return null;            }            mProcessNames.put(processName, app.uid, app);            if (isolated) {                mIsolatedProcesses.put(app.uid, app);            }        } else {            // If this is a new package in the process, add the package to the list            app.addPackage(info.packageName, mProcessStats);        }        // If the system is not ready yet, then hold off on starting this        // process until it is.        if (!mProcessesReady                && !isAllowedWhileBooting(info)                && !allowWhileBooting) {            if (!mProcessesOnHold.contains(app)) {                mProcessesOnHold.add(app);            }            if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);            return app;        }        startProcessLocked(app, hostingType, hostingNameStr);        return (app.pid != 0) ? app : null;
获取getProcessRecordLocked当前进程记录,如果不存在,证明应用进程没有创建。app 为空,则创建newProcessRecordLocked新的ProcessRecord 进程。

startProcessLocked方法代码如下:

 private final void startProcessLocked(ProcessRecord app,            String hostingType, String hostingNameStr) {        if (app.pid > 0 && app.pid != MY_PID) {            synchronized (mPidsSelfLocked) {                mPidsSelfLocked.remove(app.pid);                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);            }            app.setPid(0);        }        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,                "startProcessLocked removing on hold: " + app);        mProcessesOnHold.remove(app);        updateCpuStats();        .........            // Start the process.  It will either succeed and return a result containing            // the PID of the new process, or else throw a RuntimeException.            Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",                    app.processName, uid, uid, gids, debugFlags, mountExternal,                    app.info.targetSdkVersion, app.info.seinfo, null);            BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();            synchronized (bs) {                if (bs.isOnBattery()) {                    bs.getProcessStatsLocked(app.uid, app.processName).incStartsLocked();                }            }            EventLog.writeEvent(EventLogTags.AM_PROC_START,                    UserHandle.getUserId(uid), startResult.pid, uid,                    app.processName, hostingType,                    hostingNameStr != null ? hostingNameStr : "");            if (app.persistent) {                Watchdog.getInstance().processStarted(app.processName, startResult.pid);            }<span style="white-space:pre"></span>..........            synchronized (mPidsSelfLocked) {                this.mPidsSelfLocked.put(startResult.pid, app);                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);                msg.obj = app;                mHandler.sendMessageDelayed(msg, startResult.usingWrapper                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);            }        } catch (RuntimeException e) {            // XXX do better error recovery.            app.setPid(0);            Slog.e(TAG, "Failure starting process " + app.processName, e);        }    }
1.先移除PROC_START_TIMEOUT_MSG消息,再延迟10秒再发送,这里相当一个超时设置,如果应用程序在10后,还没有启动完成就会anr。

2.  Zygote创建应用进程,同时加载ActivityThread类的main方法 。

分析到这里,我第一时间感觉疑惑,似乎忘记我们要干的“正事”启动activity,算了,我们还是继续分析下去,看ActivityThread的main方法:

 Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        AsyncTask.init();        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();
1.创建looper,并且在后面进入消息循环队列。

2.创建ActivityThread 对象,同时调用attach方法,看一下attach方法:

  if (!system) {            ViewRootImpl.addFirstDrawHandler(new Runnable() {                @Override                public void run() {                    ensureJitEnabled();                }            });            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",                                                    UserHandle.myUserId());            RuntimeInit.setApplicationObject(mAppThread.asBinder());            IActivityManager mgr = ActivityManagerNative.getDefault();            try {                mgr.attachApplication(mAppThread);            } catch (RemoteException ex) {                // Ignore            }        }
这里通过binder机制,最终会调到AMS里面的attachApplication方法:

    public final void attachApplication(IApplicationThread thread) {        synchronized (this) {            int callingPid = Binder.getCallingPid();            final long origId = Binder.clearCallingIdentity();            attachApplicationLocked(thread, callingPid);            Binder.restoreCallingIdentity(origId);        }    }
重点分析attachApplicationLocked方法:

    private final boolean attachApplicationLocked(IApplicationThread thread,            int pid) {<span style="white-space:pre"></span>.....................        // If this application record is still attached to a previous        // process, clean it up now.        if (app.thread != null) {            handleAppDiedLocked(app, true, true);        }<span style="white-space:pre"></span>......        app.makeActive(thread, mProcessStats);        app.curAdj = app.setAdj = -100;        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;        app.forcingToForeground = null;        app.foregroundServices = false;        app.hasShownUi = false;        app.debugging = false;        app.cached = false;        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);<span style="white-space:pre"></span>......            ensurePackageDexOpt(app.instrumentationInfo != null                    ? app.instrumentationInfo.packageName                    : app.info.packageName);            if (app.instrumentationClass != null) {                ensurePackageDexOpt(app.instrumentationClass.getPackageName());            }            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "                    + processName + " with config " + mConfiguration);            ApplicationInfo appInfo = app.instrumentationInfo != null                    ? app.instrumentationInfo : app.info;            app.compat = compatibilityInfoForPackageLocked(appInfo);            if (profileFd != null) {                profileFd = profileFd.dup();            }            thread.bindApplication(processName, appInfo, providers,                    app.instrumentationClass, profileFile, profileFd, profileAutoStop,                    app.instrumentationArguments, app.instrumentationWatcher,                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,                    isRestrictedBackupMode || !normalMode, app.persistent,                    new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),                    mCoreSettingsObserver.getCoreSettingsLocked());            updateLruProcessLocked(app, false, null);            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.w(TAG, "Exception thrown during bind!", e);            app.resetPackageList(mProcessStats);            app.unlinkDeathRecipient();            startProcessLocked(app, "bind fail", processName);            return false;        }<span style="white-space:pre"></span> if (normalMode) {            try {                if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {                    didSomething = true;                }            } catch (Exception e) {                badApp = true;            }        }<span style="white-space:pre"></span>............        if (!didSomething) {            updateOomAdjLocked();        }        return true;    }
1.设置应用进程的属性,类似curAdj 等,同时移除前面PROC_START_TIMEOUT_MSG 消息。

2.bindApplication设置应用进程的instrumentation providers。

3.运行mStackSupervisor.attachApplicationLocked启动第一个activity.

呵呵,到这里看到与activity启动相关的东西,但我们还是看一下bindApplication什么作用?

再看bindApplication方法:

            if (services != null) {                // Setup the service cache in the ServiceManager                ServiceManager.initServiceCache(services);            }            setCoreSettings(coreSettings);            AppBindData data = new AppBindData();            data.processName = processName;            data.appInfo = appInfo;            data.providers = providers;            data.instrumentationName = instrumentationName;            data.instrumentationArgs = instrumentationArgs;            data.instrumentationWatcher = instrumentationWatcher;            data.instrumentationUiAutomationConnection = instrumentationUiConnection;            data.debugMode = debugMode;            data.enableOpenGlTrace = enableOpenGlTrace;            data.restrictedBackupMode = isRestrictedBackupMode;            data.persistent = persistent;            data.config = config;            data.compatInfo = compatInfo;            data.initProfileFile = profileFile;            data.initProfileFd = profileFd;            data.initAutoStopProfiler = false;            sendMessage(H.BIND_APPLICATION, data);        }
很简单,只是赋值而已,然后发送BIND_APPLICATION消息。

然后调用handleBindApplication方法:

    private void handleBindApplication(AppBindData data) {        mBoundApplication = data;        mConfiguration = new Configuration(data.config);        mCompatConfiguration = new Configuration(data.config);        mProfiler = new Profiler();        mProfiler.profileFile = data.initProfileFile;        mProfiler.profileFd = data.initProfileFd;        mProfiler.autoStopProfiler = data.initAutoStopProfiler;        // send up app name; do this *before* waiting for debugger        Process.setArgV0(data.processName);        android.ddm.DdmHandleAppName.setAppName(data.processName,                                                UserHandle.myUserId());        if (data.persistent) {            // Persistent processes on low-memory devices do not get to            // use hardware accelerated drawing, since this can add too much            // overhead to the process.            if (!ActivityManager.isHighEndGfx()) {                HardwareRenderer.disable(false);            }        }                if (mProfiler.profileFd != null) {            mProfiler.startProfiling();        }        // If the app is Honeycomb MR1 or earlier, switch its AsyncTask        // implementation to use the pool executor.  Normally, we use the        // serialized executor as the default. This has to happen in the        // main thread so the main looper is set right.        if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {            AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);        }        /*         * Before spawning a new process, reset the time zone to be the system time zone.         * This needs to be done because the system time zone could have changed after the         * the spawning of this process. Without doing this this process would have the incorrect         * system time zone.         */        TimeZone.setDefault(null);        /*         * Initialize the default locale in this process for the reasons we set the time zone.         */        Locale.setDefault(data.config.locale);        /*         * Update the system configuration since its preloaded and might not         * reflect configuration changes. The configuration object passed         * in AppBindData can be safely assumed to be up to date         */        mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);        mCurDefaultDisplayDpi = data.config.densityDpi;        applyCompatConfiguration(mCurDefaultDisplayDpi);        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);        /**         * Switch this process to density compatibility mode if needed.         */        if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)                == 0) {            mDensityCompatMode = true;            Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);        }        updateDefaultDensity();        final ContextImpl appContext = new ContextImpl();        appContext.init(data.info, null, this);        if (!Process.isIsolated()) {            final File cacheDir = appContext.getCacheDir();            if (cacheDir != null) {                // Provide a usable directory for temporary files                System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());                    setupGraphicsSupport(data.info, cacheDir);            } else {                Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");            }        }        /**         * For system applications on userdebug/eng builds, log stack         * traces of disk and network access to dropbox for analysis.         */        if ((data.appInfo.flags &             (ApplicationInfo.FLAG_SYSTEM |              ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {            StrictMode.conditionallyEnableDebugLogging();        }        /**         * For apps targetting SDK Honeycomb or later, we don't allow         * network usage on the main event loop / UI thread.         *         * Note to those grepping:  this is what ultimately throws         * NetworkOnMainThreadException ...         */        if (data.appInfo.targetSdkVersion > 9) {            StrictMode.enableDeathOnNetwork();        }        if (data.debugMode != IApplicationThread.DEBUG_OFF) {            // XXX should have option to change the port.            Debug.changeDebugPort(8100);            if (data.debugMode == IApplicationThread.DEBUG_WAIT) {                Slog.w(TAG, "Application " + data.info.getPackageName()                      + " is waiting for the debugger on port 8100...");                IActivityManager mgr = ActivityManagerNative.getDefault();                try {                    mgr.showWaitingForDebugger(mAppThread, true);                } catch (RemoteException ex) {                }                Debug.waitForDebugger();                try {                    mgr.showWaitingForDebugger(mAppThread, false);                } catch (RemoteException ex) {                }            } else {                Slog.w(TAG, "Application " + data.info.getPackageName()                      + " can be debugged on port 8100...");            }        }        // Enable OpenGL tracing if required        if (data.enableOpenGlTrace) {            GLUtils.setTracingLevel(1);        }        // Allow application-generated systrace messages if we're debuggable.        boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;        Trace.setAppTracingAllowed(appTracingAllowed);        /**         * Initialize the default http proxy in this process for the reasons we set the time zone.         */        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);        if (b != null) {            // In pre-boot mode (doing initial launch to collect password), not            // all system is up.  This includes the connectivity service, so don't            // crash if we can't get it.            IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);            try {                ProxyProperties proxyProperties = service.getProxy();                Proxy.setHttpProxySystemProperty(proxyProperties);            } catch (RemoteException e) {}        }        if (data.instrumentationName != null) {            InstrumentationInfo ii = null;            try {                ii = appContext.getPackageManager().                    getInstrumentationInfo(data.instrumentationName, 0);            } catch (PackageManager.NameNotFoundException e) {            }            if (ii == null) {                throw new RuntimeException(                    "Unable to find instrumentation info for: "                    + data.instrumentationName);            }            mInstrumentationAppDir = ii.sourceDir;            mInstrumentationAppLibraryDir = ii.nativeLibraryDir;            mInstrumentationAppPackage = ii.packageName;            mInstrumentedAppDir = data.info.getAppDir();            mInstrumentedAppLibraryDir = data.info.getLibDir();            ApplicationInfo instrApp = new ApplicationInfo();            instrApp.packageName = ii.packageName;            instrApp.sourceDir = ii.sourceDir;            instrApp.publicSourceDir = ii.publicSourceDir;            instrApp.dataDir = ii.dataDir;            instrApp.nativeLibraryDir = ii.nativeLibraryDir;            LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,                    appContext.getClassLoader(), false, true);            ContextImpl instrContext = new ContextImpl();            instrContext.init(pi, null, this);            try {                java.lang.ClassLoader cl = instrContext.getClassLoader();                mInstrumentation = (Instrumentation)                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();            } catch (Exception e) {                throw new RuntimeException(                    "Unable to instantiate instrumentation "                    + data.instrumentationName + ": " + e.toString(), e);            }            mInstrumentation.init(this, instrContext, appContext,                   new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,                   data.instrumentationUiAutomationConnection);            if (mProfiler.profileFile != null && !ii.handleProfiling                    && mProfiler.profileFd == null) {                mProfiler.handlingProfiling = true;                File file = new File(mProfiler.profileFile);                file.getParentFile().mkdirs();                Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);            }        } else {            mInstrumentation = new Instrumentation();        }        if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {            dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();        }        // Allow disk access during application and provider setup. This could        // block processing ordered broadcasts, but later processing would        // probably end up doing the same disk access.        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();        try {            // If the app is being launched for full backup or restore, bring it up in            // a restricted environment with the base application class.            Application app = data.info.makeApplication(data.restrictedBackupMode, null);            mInitialApplication = app;            // don't bring up providers in restricted mode; they may depend on the            // app's custom Application class            if (!data.restrictedBackupMode) {                List<ProviderInfo> providers = data.providers;                if (providers != null) {                    installContentProviders(app, providers);                    // For process that contains content providers, we want to                    // ensure that the JIT is enabled "at some point".                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);                }            }            // Do this after providers, since instrumentation tests generally start their            // test thread at this point, and we don't want that racing.            try {                mInstrumentation.onCreate(data.instrumentationArgs);            }            catch (Exception e) {                throw new RuntimeException(                    "Exception thrown in onCreate() of "                    + data.instrumentationName + ": " + e.toString(), e);            }            try {                mInstrumentation.callApplicationOnCreate(app);            } catch (Exception e) {                if (!mInstrumentation.onException(app, e)) {                    throw new RuntimeException(                        "Unable to create application " + app.getClass().getName()                        + ": " + e.toString(), e);                }            }        } finally {            StrictMode.setThreadPolicy(savedPolicy);        }    }
这个方法比较长:

1.初始化的资源有关的属性Configuration display,时区,语言等。

2.初始化ApplicationInfo,并且调用oncreate实现初始化。
3.加载Instrumentation类,并进行初始化。

到这里我们基本可以确定bindApplication方法的作用:初始化应用的application数据,同时也初始化了android应用进程运行的环境。

我们继续回到mStackSupervisor.attachApplicationLocked方法:

 final String processName = app.processName;        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {            final ActivityStack stack = mStacks.get(stackNdx);            if (!isFrontStack(stack)) {                continue;            }            ActivityRecord hr = stack.topRunningActivityLocked(null);            if (hr != null) {                if (hr.app == null && app.uid == hr.info.applicationInfo.uid                        && processName.equals(hr.processName)) {                    try {                        if (headless) {                            Slog.e(TAG, "Starting activities not supported on headless device: "                                    + hr);                        } else if (realStartActivityLocked(hr, app, true, true)) {                            didSomething = true;                        }                    } catch (Exception e) {                        Slog.w(TAG, "Exception in new application when starting activity "                              + hr.intent.getComponent().flattenToShortString(), e);                        throw e;                    }                }            }        }        if (!didSomething) {            ensureActivitiesVisibleLocked(null, 0);        }
取出前台的堆栈,调用topRunningActivityLocked返回的第一个不为null,并且没有finish的activity,然后调用realStartActivityLocked启动。

细看realStartActivityLocked方法:

........................  app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,                    System.identityHashCode(r), r.info,                    new Configuration(mService.mConfiguration), r.compat,                    app.repProcState, r.icicle, results, newIntents, !andResume,                    mService.isNextTransitionForward(), profileFile, profileFd,                    profileAutoStop);.........................
最终会调用到ActivityThread的scheduleLaunchActivity方法:

           updateProcessState(procState, false);            ActivityClientRecord r = new ActivityClientRecord();            r.token = token;            r.ident = ident;            r.intent = intent;            r.activityInfo = info;            r.compatInfo = compatInfo;            r.state = state;            r.pendingResults = pendingResults;            r.pendingIntents = pendingNewIntents;            r.startsNotResumed = notResumed;            r.isForward = isForward;            r.profileFile = profileName;            r.profileFd = profileFd;            r.autoStopProfiler = autoStopProfiler;            updatePendingConfiguration(curConfig);            sendMessage(H.LAUNCH_ACTIVITY, r);
封装消息;发送LAUNCH_ACTIVITY消息。

 case LAUNCH_ACTIVITY: {                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;                    r.packageInfo = getPackageInfoNoCheck(                            r.activityInfo.applicationInfo, r.compatInfo);                    handleLaunchActivity(r, null);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
先获取LoadedApk对象,再调用handleLaunchActivity方法:

 private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {        // If we are getting ready to gc after going to the background, well        // we are back active so skip it.        unscheduleGcIdler();        if (r.profileFd != null) {            mProfiler.setProfiler(r.profileFile, r.profileFd);            mProfiler.startProfiling();            mProfiler.autoStopProfiler = r.autoStopProfiler;        }        // Make sure we are running with the most recent config.        handleConfigurationChanged(null, null);        if (localLOGV) Slog.v(            TAG, "Handling launch of " + r);        Activity a = performLaunchActivity(r, customIntent);        if (a != null) {            r.createdConfig = new Configuration(mConfiguration);            Bundle oldState = r.state;            handleResumeActivity(r.token, false, r.isForward,                    !r.activity.mFinished && !r.startsNotResumed);
我们来先看一下performLaunchActivity方法:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");        ActivityInfo aInfo = r.activityInfo;        if (r.packageInfo == null) {            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,                    Context.CONTEXT_INCLUDE_CODE);        }        ComponentName component = r.intent.getComponent();        if (component == null) {            component = r.intent.resolveActivity(                mInitialApplication.getPackageManager());            r.intent.setComponent(component);        }        if (r.activityInfo.targetActivity != null) {            component = new ComponentName(r.activityInfo.packageName,                    r.activityInfo.targetActivity);        }        Activity activity = null;        try {            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();            activity = mInstrumentation.newActivity(                    cl, component.getClassName(), r.intent);            StrictMode.incrementExpectedActivityCount(activity.getClass());            r.intent.setExtrasClassLoader(cl);            if (r.state != null) {                r.state.setClassLoader(cl);            }        } catch (Exception e) {            if (!mInstrumentation.onException(activity, e)) {                throw new RuntimeException(                    "Unable to instantiate activity " + component                    + ": " + e.toString(), e);            }        }        try {            Application app = r.packageInfo.makeApplication(false, mInstrumentation);            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);            if (localLOGV) Slog.v(                    TAG, r + ": app=" + app                    + ", appName=" + app.getPackageName()                    + ", pkg=" + r.packageInfo.getPackageName()                    + ", comp=" + r.intent.getComponent().toShortString()                    + ", dir=" + r.packageInfo.getAppDir());            if (activity != null) {                Context appContext = createBaseContextForActivity(r, activity);                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());                Configuration config = new Configuration(mCompatConfiguration);                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "                        + r.activityInfo.name + " with config " + config);                activity.attach(appContext, this, getInstrumentation(), r.token,                        r.ident, app, r.intent, r.activityInfo, title, r.parent,                        r.embeddedID, r.lastNonConfigurationInstances, config);                if (customIntent != null) {                    activity.mIntent = customIntent;                }                r.lastNonConfigurationInstances = null;                activity.mStartedActivity = false;                int theme = r.activityInfo.getThemeResource();                if (theme != 0) {                    activity.setTheme(theme);                }                activity.mCalled = false;                mInstrumentation.callActivityOnCreate(activity, r.state);                if (!activity.mCalled) {                    throw new SuperNotCalledException(                        "Activity " + r.intent.getComponent().toShortString() +                        " did not call through to super.onCreate()");                }                r.activity = activity;                r.stopped = true;                if (!r.activity.mFinished) {                    activity.performStart();                    r.stopped = false;                }                if (!r.activity.mFinished) {                    if (r.state != null) {                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);                    }                }                if (!r.activity.mFinished) {                    activity.mCalled = false;                    mInstrumentation.callActivityOnPostCreate(activity, r.state);                    if (!activity.mCalled) {                        throw new SuperNotCalledException(                            "Activity " + r.intent.getComponent().toShortString() +                            " did not call through to super.onPostCreate()");                    }                }            }            r.paused = true;            mActivities.put(r.token, r);        } catch (SuperNotCalledException e) {            throw e;        } catch (Exception e) {            if (!mInstrumentation.onException(activity, e)) {                throw new RuntimeException(                    "Unable to start activity " + component                    + ": " + e.toString(), e);            }        }        return activity;    }
1.利用classLoader加载activity类。

2.生成上下文,同时调用callActivityOnCreate调用oncreate方法。


再回到上面一点看一下:handleResumeActivity方法,设置window窗口的显示,调用 r.activity.performResume() 方法执行activity的onresume方法。















 







0 0