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方法。
- android学习--Activity及应用启动过程
- 学习android内核 -- Activity启动过程
- android activity 启动 过程
- Android-Activity启动过程
- [Android]Activity启动过程
- 【Android源码学习】应用启动过程
- Activity应用及启动模式
- Android Activity的4中启动模式及应用场景
- android 学习笔记 Activity 和service 的启动过程
- (转载)android学习之旅-activity启动过程
- Activity的启动过程(Android开发艺术探索学习笔记)
- android Activity启动过程-startActivity
- Android Activity的启动过程
- Android Activity的启动过程
- Android Activity的启动过程
- Android应用启动过程
- Android-应用启动过程
- Android应用开发学习笔记之启动另外一个Activity
- 【文件传输】linux与window文件如何相互传输
- CodeVs 1148 传球游戏
- Binary Tree Zigzag Level Order Traversal
- 最新出炉程序员使用说明书
- 修改View的透明度
- android学习--Activity及应用启动过程
- SOJ 1021. Couples
- 网络流之最大流算法(ford-fulkerson)
- UNIX-LINUX平台可执行文件格式分析
- eXeScope之类的程序资源修改器的使用,很牛! 【只是针对VC++和DELPHI写的程序】
- 飘逸的python - 一个简单的AST(抽象语法树)
- hdu 5008 Boring String Problem(后缀数组)
- Linux下的lds链接脚本基础
- java中在方法中定义不定长参数示例