12.源码阅读(app启动流程-android api 26)
activity的啟動流程之前已經通過源碼了解了,那么app的啟動流程是怎樣的,從我們按下app的圖標,到應用啟動起來顯示出畫面,中間都經歷了什么?
安卓是基于java的,所以和java有一定的相似性,一個java程序的起點是main,那么android是不是也是如此?事實上,正如猜想我們找到ActivityTread這個類中的main方法,這里就是app啟動的源頭
public static void main(String[] args) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");SamplingProfilerIntegration.start();CloseGuard.setEnabled(false);//初始化內存卡環境Environment.initForCurrentUser();// Set the reporter for event logging in libcoreEventLogger.setReporter(new EventLoggingReporter());//處理簽名相關的東西,驗證之類的餓AndroidKeyStoreProvider.install();// 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>");//應用程序一啟動就初始化全局的looperLooper.prepareMainLooper();ActivityThread thread = new ActivityThread();//這個是主要的方法,false表示不是系統應用,第三方app默認都是falsethread.attach(false);//初始化主線程handler,在ActivityTread加載的時候就已經生成了if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}正式開始加載app
private void attach(boolean system) {sCurrentActivityThread = this;mSystemThread = system;if (!system) {//第三方應用//ViewRootImpl相關......//這個已經很熟悉了,我們要去找IActivityManager的實現類ActivityManagerServicefinal IActivityManager mgr = ActivityManagerNative.getDefault();try {//進入ActivityManagerServicemgr.attachApplication(mAppThread);} catch (RemoteException ex) {// Ignore}//可以看到這里是內存使用量的一個監聽,當app已經占用的空間大于系統分配給//這個app最大空間的四分之三的時候,java虛擬機會觸發gc清理空間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) {}}}});} 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 libcoreDropBox.setReporter(new DropBoxReporter());//設置Configuration改變的監聽ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {@Overridepublic void onConfigurationChanged(Configuration newConfig) {synchronized (mResourcesManager) {// We need to apply this change to the resources// immediately, because upon returning the view// hierarchy will be informed about it.if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {// This actually changed the resources! Tell// everyone about it.if (mPendingConfiguration == null ||mPendingConfiguration.isOtherSeqNewer(newConfig)) {mPendingConfiguration = newConfig;sendMessage(H.CONFIGURATION_CHANGED, newConfig);}}}}@Overridepublic void onLowMemory() {}@Overridepublic void onTrimMemory(int level) {}});}進入ActivityManagerService
@Overridepublic final void attachApplication(IApplicationThread thread) {synchronized (this) {int callingPid = Binder.getCallingPid();final long origId = Binder.clearCallingIdentity();attachApplicationLocked(thread, callingPid);Binder.restoreCallingIdentity(origId);}} private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {......//thread就是傳過來的final ApplicationThread mAppThread = new ApplicationThread();它在ActivityThread加載的時候就已經創建thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,isRestrictedBackupMode || !normalMode, app.persistent,new Configuration(mConfiguration), app.compat,getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked());......// See if the top visible activity is waiting to run in this process...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);} catch (Exception e) {Slog.wtf(TAG, "Exception thrown starting services in " + app, e);badApp = true;}}......回到ActivityThread中
public final void bindApplication(String processName, ApplicationInfo appInfo,List<ProviderInfo> providers, ComponentName instrumentationName,ProfilerInfo profilerInfo, Bundle instrumentationArgs,IInstrumentationWatcher instrumentationWatcher,IUiAutomationConnection instrumentationUiConnection, int debugMode,boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,Bundle coreSettings) {if (services != null) {// Setup the service cache in the ServiceManagerServiceManager.initServiceCache(services);}setCoreSettings(coreSettings);/** Two possible indications that this package could be* sharing its runtime with other packages:** 1.) the sharedUserId attribute is set in the manifest,* indicating a request to share a VM with other* packages with the same sharedUserId.** 2.) the application element of the manifest has an* attribute specifying a non-default process name,* indicating the desire to run in another packages VM.** If sharing is enabled we do not have a unique application* in a process and therefore cannot rely on the package* name inside the runtime.*/IPackageManager pm = getPackageManager();android.content.pm.PackageInfo pi = null;try {pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());} catch (RemoteException e) {}if (pi != null) {boolean sharedUserIdSet = (pi.sharedUserId != null);boolean processNameNotDefault =(pi.applicationInfo != null &&!appInfo.packageName.equals(pi.applicationInfo.processName));boolean sharable = (sharedUserIdSet || processNameNotDefault);// Tell the VMRuntime about the application, unless it is shared// inside a process.if (!sharable) {VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir,appInfo.processName);}}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.initProfilerInfo = profilerInfo;sendMessage(H.BIND_APPLICATION, data);}handler接收消息進行處理
case BIND_APPLICATION:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");AppBindData data = (AppBindData)msg.obj;handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break; private void handleBindApplication(AppBindData data) {......//反射加載到Instrumentation對象或者當條件不滿足時,直接new出來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);}....else {mInstrumentation = new Instrumentation();}......try {//調用Application的onCreate 方法mInstrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!mInstrumentation.onException(app, e)) {throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}} }Application是啟動了,那么到了這里似乎已經無法繼續往下走了,activity是如何啟動的,我們回到ActivityManagerService中,在上邊的那代碼下如下,現在已經知道了bindApplication最終執行到了Application的onCreate,那么下邊的方法attachApplicationLocked將會是尋找Activity啟動的線索
private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {......//thread就是傳過來的final ApplicationThread mAppThread = new ApplicationThread();它在ActivityThread加載的時候就已經創建thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,isRestrictedBackupMode || !normalMode, app.persistent,new Configuration(mConfiguration), app.compat,getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked());......// See if the top visible activity is waiting to run in this process...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);} catch (Exception e) {Slog.wtf(TAG, "Exception thrown starting services in " + app, e);badApp = true;}}......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 (!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 {//真的開始啟動activity了if (realStartActivityLocked(hr, app, true, true)) {didSomething = true;}} catch (RemoteException e) {Slog.w(TAG, "Exception in new application when starting activity "+ hr.intent.getComponent().flattenToShortString(), e);throw e;}}}}}if (!didSomething) {ensureActivitiesVisibleLocked(null, 0);}return didSomething;}到了realStartActivityLocked這個方法這里,后邊的東西就和之前看過的activity的啟動流程相同了,所以就不再往下看了,感興趣可以看看我的另一篇03.源碼閱讀(Activity啟動流程--android api 23)
總結
以上是生活随笔為你收集整理的12.源码阅读(app启动流程-android api 26)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大四 PHP《上传文件》
- 下一篇: 机器学习基础 --- numpy的基本使