理解 Android 程式啟動之全過程
原文連結:
一. 概述
Android系統將程式做得很友好的封裝,對於上層app開發者來說程式幾乎是透明的. 瞭解Android的朋友,一定知道Android四大元件,但對於程式可能會相對較陌生. 一個程式裡面可以跑多個app(透過share uid的方式), 一個app也可以跑在多個程式裡(透過配置Android:process屬性).
再進一步程式是如何建立的, 可能很多人不知道fork的存在. 在我的文章 集中一點詳細介紹了Process.start
的過程是如何一步步建立程式.本文則是從另個角度來全域性性講解全過程所涉及的根脈, 先來看看AMS.startProcessLocked方法.
二. 四大元件與程式
2.1 startProcessLocked
在ActivityManagerService.java
關於啟動程式有4個同名不同引數的過載方法, 為了便於說明,以下4個方法依次記為1(a)
,1(b)
, 2(a)
, 2(b)
:
//方法 1(a)final ProcessRecord startProcessLocked( String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge)//方法 1(b)final ProcessRecord startProcessLocked( String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler)//方法 2(a)private final void startProcessLocked( ProcessRecord app, String hostingType, String hostingNameStr)//方法 2(b)private final void startProcessLocked( ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs)
1(a) ==> 1(b): 方法1(a)將isolatedUid=0,其他引數賦值為null,再呼叫給1(b)
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType, hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); }
2(a) ==> 2(b): 方法2(a)將其他3個引數abiOverride,entryPoint, entryPointArgs賦值為null,再呼叫給2(b)
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) { startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */, null /* entryPoint */, null /* entryPointArgs */); }
小結:
1(a),1(b)的第一個引數為String型別的程式名processName,
2(a), 2(b)的第一個引數為ProcessRecord型別程式記錄資訊ProcessRecord;
1系列的方法最終呼叫到2系列的方法;
2.2 四大元件與程式
Activity, Service, ContentProvider, BroadcastReceiver這四大元件,在啟動的過程,當其所承載的程式不存在時需要先建立程式. 這個建立程式的過程是呼叫前面講到的startProcessLocked方法1(a) . 呼叫流程: 1(a) => 1(b) ==> 2(b). 下面再簡單說說這4大元件與程式建立是在何時需要建立的.
2.2.1 Activity
啟動Activity過程: 呼叫startActivity,該方法經過層層呼叫,最終會呼叫ActivityStackSupervisor.java中的startSpecificActivityLocked
,當activity所屬程式還沒啟動的情況下,則需要建立相應的程式.
[-> ActivityStackSupervisor.java]
void startSpecificActivityLocked(...) { ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); if (app != null && app.thread != null) { ... //程式已建立的case return } mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }
2.2.2 Service
啟動服務過程: 呼叫startService,該方法經過層層呼叫,最終會呼叫ActiveServices.java中的bringUpServiceLocked
,當Service程式沒有啟動的情況(app==null), 則需要建立相應的程式. 更多關於Service, 見
[-> ActiveServices.java]
private final String bringUpServiceLocked(...){ ... ProcessRecord app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); if (app == null) { if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated, false)) == null) { ... } } ... }
2.2.3 ContentProvider
ContentProvider處理過程: 呼叫ContentResolver.query該方法經過層層呼叫, 最終會呼叫到AMS.java中的getContentProviderImpl
,當ContentProvider所對應程式不存在,則需要建立新程式. 更多關於ContentProvider,見
[-> AMS.java]
private final ContentProviderHolder getContentProviderImpl(...) { ... ProcessRecord proc = getProcessRecordLocked(cpi.processName, cpr.appInfo.uid, false); if (proc != null && proc.thread != null) { ... //程式已建立的case } else { proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName,cpi.name), false, false, false); } ... }
2.2.4 Broadcast
廣播處理過程: 呼叫sendBroadcast,該方法經過層層呼叫, 最終會呼叫到BroadcastQueue.java中的processNextBroadcast
,當BroadcastReceiver所對應的程式尚未啟動,則建立相應程式. 更多關於broadcast, 見.
[-> BroadcastQueue.java]
final void processNextBroadcast(boolean fromMsg) { ... ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid, false); if (app != null && app.thread != null) { ... //程式已建立的case return } if ((r.curApp=mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent, (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) { ... } ... }
2.3 小節
Activity, Service, ContentProvider, BroadcastReceiver這四大元件在啟動時,當所承載的程式不存在時,都需要建立. 程式的建立過程交由系統程式system_server來完成的.
簡稱:
ATP: ApplicationThreadProxy
AT: ApplicationThread (繼承於ApplicationThreadNative)
AMP: ActivityManagerProxy
AMS: ActivityManagerService (繼承於ActivityManagerNative)
圖解:
system_server程式中呼叫
startProcessLocked
方法,該方法最終透過socket方式,將需要建立新程式的訊息告知Zygote程式,並阻塞等待Socket返回新建立程式的pid;Zygote程式接收到system_server傳送過來的訊息, 則透過fork的方法,將zygote自身程式複製生成新的程式,並將ActivityThread相關的資源載入到新程式app process,這個程式可能是用於承載activity等元件;
建立完新程式後fork返回兩次, 在新程式app process向servicemanager查詢system_server程式中binder服務端AMS,獲取相對應的Client端,也就是AMP. 有了這一對binder c/s對, 那麼app process便可以透過binder向跨程式system_server傳送請求,即attachApplication()
system_server程式接收到相應binder操作後,經過多次呼叫,利用ATP向app process傳送binder請求, 即bindApplication.
system_server擁有ATP/AMS, 每一個新建立的程式都會有一個相應的AT/AMS,從而可以跨程式 進行相互通訊. 這便是程式建立過程的完整生態鏈.
四大元件的程式建立時機:
元件 | 建立方法 |
---|---|
Activity | ASS.startSpecificActivityLocked() |
Service | ActiveServices.bringUpServiceLocked() |
ContentProvider | AMS.getContentProviderImpl() |
Broadcast | BroadcastQueue.processNextBroadcast() |
三. 程式啟動全過程
前面剛已介紹四大元件的建立程式的過程是呼叫1(a) startProcessLocked
方法,該方法會再呼叫1(b)方法. 接下來從該方法開始往下講述.
3.1 AMS.startProcessLocked
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { long startTime = SystemClock.elapsedRealtime(); ProcessRecord app; if (!isolated) { //根據程式名和uid檢查相應的ProcessRecord app = getProcessRecordLocked(processName, info.uid, keepIfLarge); if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) { //如果當前處於後臺程式,檢查當前程式是否處於bad程式列表 if (mBadProcesses.get(info.processName, info.uid) != null) { return null; } } else { //當使用者明確地啟動程式,則清空crash次數,以保證其不處於bad程式直到下次再彈出crash對話方塊。 mProcessCrashTimes.remove(info.processName, info.uid); if (mBadProcesses.get(info.processName, info.uid) != null) { mBadProcesses.remove(info.processName, info.uid); if (app != null) { app.bad = false; } } } } else { //對於孤立程式,無法再利用已存在的程式 app = null; } //當存在ProcessRecord,且已分配pid(正在啟動或者已經啟動), // 且caller並不認為該程式已死亡或者沒有thread物件attached到該程式.則不應該清理該程式 if (app != null && app.pid > 0) { if (!knownToBeDead || app.thread == null) { //如果這是程式中新package,則新增到列表 app.addPackage(info.packageName, info.versionCode, mProcessStats); return app; } //當ProcessRecord已經被attached到先前的一個程式,則殺死並清理該程式 killProcessGroup(app.info.uid, app.pid); handleAppDiedLocked(app, true, true); } String hostingNameStr = hostingName != null? hostingName.flattenToShortString() : null; if (app == null) { // 建立新的Process Record物件 app = newProcessRecordLocked(info, processName, isolated, isolatedUid); if (app == null) { return null; } app.crashHandler = crashHandler; } else { //如果這是程式中新package,則新增到列表 app.addPackage(info.packageName, info.versionCode, mProcessStats); } //當系統未準備完畢,則將當前程式加入到mProcessesOnHold if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) { if (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } return app; } // 啟動程式【見小節3.2】 startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs); return (app.pid != 0) ? app : null; }
主要功能:
對於非isolated程式,則根據程式名和uid來查詢相應的ProcessRecord結構體. 如果當前程式處於後臺且當前程式處於mBadProcesses列表,則直接返回;否則清空crash次數,以保證其不處於bad程式直到下次再彈出crash對話方塊。
當存在ProcessRecord,且已分配pid(正在啟動或者已經啟動)的情況下
當caller並不認為該程式已死亡或者沒有thread物件attached到該程式.則不應該清理該程式,則直接返回;
否則殺死並清理該程式;
當ProcessRecord為空則新建一個,當建立失敗則直接返回;
當系統未準備完畢,則將當前程式加入到mProcessesOnHold, 並直接返回;
最後啟動新程式,其中引數含義:
hostingType可取值為”activity”,”service”,”broadcast”,”content provider”;
hostingNameStr資料型別為ComponentName,代表的是具體相對應的元件名.
另外, 程式的uid是在程式真正建立之前呼叫newProcessRecordLocked
方法來獲取的uid, 這裡會考慮是否為isolated的情況.
3.2 AMS.startProcessLocked
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { long startTime = SystemClock.elapsedRealtime(); //當app的pid大於0且不是當前程式的pid,則從mPidsSelfLocked中移除該app.pid if (app.pid > 0 && app.pid != MY_PID) { synchronized (mPidsSelfLocked) { mPidsSelfLocked.remove(app.pid); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } app.setPid(0); } //從mProcessesOnHold移除該app mProcessesOnHold.remove(app); updateCpuStats(); //更新cpu統計資訊 try { try { if (AppGlobals.getPackageManager().isPackageFrozen(app.info.packageName)) { //當前package已被凍結,則丟擲異常 throw new RuntimeException("Package " + app.info.packageName + " is frozen!"); } } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } int uid = app.uid; int[] gids = null; int mountExternal = Zygote.MOUNT_EXTERNAL_NONE; if (!app.isolated) { int[] permGids = null; try { //透過Package Manager獲取gids final IPackageManager pm = AppGlobals.getPackageManager(); permGids = pm.getPackageGids(app.info.packageName, app.userId); MountServiceInternal mountServiceInternal = LocalServices.getService( MountServiceInternal.class); mountExternal = mountServiceInternal.getExternalStorageMountMode(uid, app.info.packageName); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } //新增共享app和gids,用於app直接共享資源 if (ArrayUtils.isEmpty(permGids)) { gids = new int[2]; } else { gids = new int[permGids.length + 2]; System.arraycopy(permGids, 0, gids, 2, permGids.length); } gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid)); gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid)); } //根據不同引數,設定相應的debugFlags ... app.gids = gids; app.requiredAbi = requiredAbi; app.instructionSet = instructionSet; boolean isActivityProcess = (entryPoint == null); if (entryPoint == null) entryPoint = "android.app.ActivityThread"; //請求Zygote建立新程式[見3.3] Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs); ... if (app.persistent) { Watchdog.getInstance().processStarted(app.processName, startResult.pid); } //重置ProcessRecord的成員變數 app.setPid(startResult.pid); app.usingWrapper = startResult.usingWrapper; app.removed = false; app.killed = false; app.killedByAm = false; //將新建立的程式加入到mPidsSelfLocked synchronized (mPidsSelfLocked) { this.mPidsSelfLocked.put(startResult.pid, app); if (isActivityProcess) { Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG); msg.obj = app; //延遲傳送訊息PROC_START_TIMEOUT_MSG mHandler.sendMessageDelayed(msg, startResult.usingWrapper ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); } } } catch (RuntimeException e) { app.setPid(0); //程式建立失敗,則重置pid } }
根據不同引數,設定相應的debugFlags,比如在AndroidManifest.xml中設定androidd:debuggable為true,代表app執行在debug模式,則增加debugger標識以及開啟JNI check功能
呼叫Process.start來建立新程式;
重置ProcessRecord的成員變數, 一般情況下超時10s後傳送PROC_START_TIMEOUT_MSG的handler訊息;
關於Process.start()是透過socket通訊告知Zygote建立fork子程式,建立新程式後將ActivityThread類載入到新程式,並呼叫ActivityThread.main()方法。詳細過程見,接下來進入AT.main方法.
3.3 ActivityThread.main
[-> ActivityThread.java]
public static void main(String[] args) { //效能統計預設是關閉的 SamplingProfilerIntegration.start(); //將當前程式所在userId賦值給sCurrentUser Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); AndroidKeyStoreProvider.install(); //確保可信任的CA證照存放在正確的位置 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0(""); //建立主執行緒的Looper物件, 該Looper是不執行退出 Looper.prepareMainLooper(); //建立ActivityThread物件 ActivityThread thread = new ActivityThread(); //建立Binder通道 【見流程3.4】 thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } // 當設定為true時,可開啟訊息佇列的debug log資訊 if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); //訊息迴圈執行 throw new RuntimeException("Main thread loop unexpectedly exited"); }
建立主執行緒的Looper物件: 該Looper是不執行退出. 也就是說主執行緒的Looper是在程式建立完成時自動建立完成,如果子執行緒也需要建立handler通訊過程,那麼就需要手動建立Looper物件,並且每個執行緒只能建立一次.
建立ActivityThread物件
thread = new ActivityThread()
: 該過程會初始化幾個很重要的變數:mAppThread = new ApplicationThread()
mLooper = Looper.myLooper()
mH = new H(),
H
繼承於Handler
;用於處理元件的生命週期.attach過程是當前主執行緒向system_server程式通訊的過程, 將thread資訊告知AMS.接下來還會進一步說明該過程.
sMainThreadHandler透過getHandler(),獲取的物件便是
mH
,這就是主執行緒的handler物件.
之後主執行緒呼叫Looper.loop(),進入訊息迴圈狀態, 當沒有訊息時主執行緒進入休眠狀態, 一旦有訊息到來則喚醒主執行緒並執行相關操作.
3.4. ActivityThread.attach
[-> ActivityThread.java]
private void attach(boolean system) { sCurrentActivityThread = this; mSystemThread = system; if (!system) { //開啟虛擬機器的jit即時編譯功能 ViewRootImpl.addFirstDrawHandler(new Runnable() { @Override public void run() { ensureJitEnabled(); } }); android.ddm.DdmHandleAppName.setAppName("", UserHandle.myUserId()); RuntimeInit.setApplicationObject(mAppThread.asBinder()); //建立ActivityManagerProxy物件 final IActivityManager mgr = ActivityManagerNative.getDefault(); try { //呼叫基於IActivityManager介面的Binder通道【見流程3.5】 mgr.attachApplication(mAppThread); } catch (RemoteException ex) { } //觀察是否快接近heap的上限 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)) { mSomeActivitiesChanged = false; try { //當已用記憶體超過最大記憶體的3/4,則請求釋放記憶體空間 mgr.releaseSomeActivities(mAppThread); } catch (RemoteException e) { } } } }); } else { ... } //新增dropbox日誌到libcore DropBox.setReporter(new DropBoxReporter()); //新增Config回撥介面 ViewRootImpl.addConfigCallback(new ComponentCallbacks2() { @Override public void onConfigurationChanged(Configuration newConfig) { synchronized (mResourcesManager) { if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) { if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(newConfig)) { mPendingConfiguration = newConfig; sendMessage(H.CONFIGURATION_CHANGED, newConfig); } } } } @Override public void onLowMemory() { } @Override public void onTrimMemory(int level) { } }); }
對於非系統attach的處理流程:
建立執行緒來開啟虛擬機器的jit即時編譯;
透過binder, 呼叫到AMS.attachApplication, 其引數mAppThread的資料型別為
ApplicationThread
觀察是否快接近heap的上限,當已用記憶體超過最大記憶體的3/4,則請求釋放記憶體空間
新增dropbox日誌到libcore
新增Config回撥介面
3.5 AMP.attachApplication
[-> ActivityManagerProxy.java]
public void attachApplication(IApplicationThread app) throws RemoteException{ Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(app.asBinder()); mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0); //【見流程3.6】 reply.readException(); data.recycle(); reply.recycle(); }
此處 descriptor = “android.app.IActivityManager”
3.6 AMN.onTransact
[-> ActivityManagerNative.java]
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { ... case ATTACH_APPLICATION_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); //獲取ApplicationThread的binder代理類 ApplicationThreadProxy IApplicationThread app = ApplicationThreadNative.asInterface( data.readStrongBinder()); if (app != null) { attachApplication(app); //此處是ActivityManagerService類中的方法 【見流程3.7】 } reply.writeNoException(); return true; } } }
3.7 AMS.attachApplication
[-> ActivityManagerService.java]
public final void attachApplication(IApplicationThread thread) { synchronized (this) { int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid); // 【見流程3.8】 Binder.restoreCallingIdentity(origId); } }
此處的thread
便是ApplicationThreadProxy物件,用於跟前面透過Process.start()所建立的程式中ApplicationThread物件進行通訊.
3.8 AMS.attachApplicationLocked
[-> ActivityManagerService.java]
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { ProcessRecord app; if (pid != MY_PID && pid >= 0) { synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); // 根據pid獲取ProcessRecord } } else { app = null; } if (app == null) { if (pid > 0 && pid != MY_PID) { //ProcessRecord為空,則殺掉該程式 Process.killProcessQuiet(pid); } else { //退出新建程式的Looper thread.scheduleExit(); } return false; } //還剛進入attach過程,此時thread應該為null,若不為null則表示該app附到上一個程式,則立刻清空 if (app.thread != null) { handleAppDiedLocked(app, true, true); } 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; } //重置程式資訊 app.makeActive(thread, mProcessStats); //執行完該語句,則app.thread便不再為空 app.curAdj = app.setAdj = -100; app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT; app.forcingToForeground = null; updateProcessForegroundLocked(app, false, false); app.hasShownUi = false; app.debugging = false; app.cached = false; app.killedByAm = false; mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); //移除程式啟動超時的訊息 //系統處於ready狀態或者該app為FLAG_PERSISTENT程式,則為true boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); Listproviders = normalMode ? generateApplicationProvidersLocked(app) : null; //app程式存在正在啟動中的provider,則超時10s後傳送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG訊息 if (providers != null && checkAppInLaunchingProvidersLocked(app)) { Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); msg.obj = app; mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT); } try { ... ensurePackageDexOpt(app.instrumentationInfo != null ? app.instrumentationInfo.packageName : app.info.packageName); ApplicationInfo appInfo = app.instrumentationInfo != null ? app.instrumentationInfo : app.info; ... // 繫結應用 [見流程3.9] 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()); //更新程式LRU佇列 updateLruProcessLocked(app, false, null); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); } catch (Exception e) { app.resetPackageList(mProcessStats); app.unlinkDeathRecipient(); //每當bind操作失敗,則重啟啟動程式, 此處有可能會導致程式無限重啟 startProcessLocked(app, "bind fail", processName); return false; } mPersistentStartingProcesses.remove(app); mProcessesOnHold.remove(app); boolean badApp = false; boolean didSomething = false; //Activity: 檢查最頂層可見的Activity是否等待在該程式中執行 if (normalMode) { try { if (mStackSupervisor.attachApplicationLocked(app)) { didSomething = true; } } catch (Exception e) { badApp = true; } } //Service: 尋找所有需要在該程式中執行的服務 if (!badApp) { try { didSomething |= mServices.attachApplicationLocked(app, processName); } catch (Exception e) { badApp = true; } } //Broadcast: 檢查是否在這個程式中有下一個廣播接收者 if (!badApp && isPendingBroadcastProcessLocked(pid)) { try { didSomething |= sendPendingBroadcastsLocked(app); } catch (Exception e) { badApp = true; } } //檢查是否在這個程式中有下一個backup代理 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) { ensurePackageDexOpt(mBackupTarget.appInfo.packageName); try { thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, compatibilityInfoForPackageLocked(mBackupTarget.appInfo), mBackupTarget.backupMode); } catch (Exception e) { badApp = true; } } if (badApp) { //殺掉bad應用 app.kill("error during init", true); handleAppDiedLocked(app, false, true); return false; } if (!didSomething) { updateOomAdjLocked(); //更新adj的值 } return true; }
根據pid從mPidsSelfLocked中查詢到相應的ProcessRecord物件app;
當app==null,意味著本次建立的程式不存在, 則直接返回.
還剛進入attach過程,此時thread應該為null,若不為null則表示該app附到上一個程式,則呼叫handleAppDiedLocked清理.
繫結死亡通知,當程式pid死亡時會透過binder死亡回撥,來通知system_server程式死亡的訊息;
重置ProcessRecord程式資訊, 此時app.thread也賦予了新值,便不再為空.
app程式存在正在啟動中的provider,則超時10s後傳送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG訊息
呼叫thread.bindApplication繫結應用程式, 後面再進一步說明
處理Provider, Activity, Service, Broadcast相應流程
下面,再來說說thread.bindApplication的過程.
3.9 ATP.bindApplication
[-> ApplicationThreadNative.java ::ApplicationThreadProxy]
class ApplicationThreadProxy implements IApplicationThread { ... public final void bindApplication(String packageName, ApplicationInfo info, Listproviders, ComponentName testName, ProfilerInfo profilerInfo, Bundle testArgs, IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection, int debugMode, boolean openGlTrace, boolean restrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map services, Bundle coreSettings) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeString(packageName); info.writeToParcel(data, 0); data.writeTypedList(providers); if (testName == null) { data.writeInt(0); } else { data.writeInt(1); testName.writeToParcel(data, 0); } if (profilerInfo != null) { data.writeInt(1); profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { data.writeInt(0); } data.writeBundle(testArgs); data.writeStrongInterface(testWatcher); data.writeStrongInterface(uiAutomationConnection); data.writeInt(debugMode); data.writeInt(openGlTrace ? 1 : 0); data.writeInt(restrictedBackupMode ? 1 : 0); data.writeInt(persistent ? 1 : 0); config.writeToParcel(data, 0); compatInfo.writeToParcel(data, 0); data.writeMap(services); data.writeBundle(coreSettings); mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } ... }
ATP經過binder ipc傳遞到ATN的onTransact過程.
3.10 ATN.onTransact
[-> ApplicationThreadNative.java]
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { ... case BIND_APPLICATION_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); String packageName = data.readString(); ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data); Listproviders = data.createTypedArrayList(ProviderInfo.CREATOR); ComponentName testName = (data.readInt() != 0) ? new ComponentName(data) : null; ProfilerInfo profilerInfo = data.readInt() != 0 ? ProfilerInfo.CREATOR.createFromParcel(data) : null; Bundle testArgs = data.readBundle(); IBinder binder = data.readStrongBinder(); IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder); binder = data.readStrongBinder(); IUiAutomationConnection uiAutomationConnection = IUiAutomationConnection.Stub.asInterface(binder); int testMode = data.readInt(); boolean openGlTrace = data.readInt() != 0; boolean restrictedBackupMode = (data.readInt() != 0); boolean persistent = (data.readInt() != 0); Configuration config = Configuration.CREATOR.createFromParcel(data); CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); HashMap services = data.readHashMap(null); Bundle coreSettings = data.readBundle(); //[見流程3.11] bindApplication(packageName, info, providers, testName, profilerInfo, testArgs, testWatcher, uiAutomationConnection, testMode, openGlTrace, restrictedBackupMode, persistent, config, compatInfo, services, coreSettings); return true; } ... }
3.11 AT.bindApplication
[-> ActivityThread.java ::ApplicationThread]
public final void bindApplication(String processName, ApplicationInfo appInfo, Listproviders, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map services, Bundle coreSettings) { if (services != null) { //將services快取起來, 減少binder檢索服務的次數 ServiceManager.initServiceCache(services); } //傳送訊息H.SET_CORE_SETTINGS setCoreSettings(coreSettings); 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); if (!sharable) { VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir, appInfo.processName); } } //初始化AppBindData, 再傳送訊息H.BIND_APPLICATION 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); }
其中setCoreSettings()過程就是呼叫sendMessage(H.SET_CORE_SETTINGS, coreSettings) 來向主執行緒傳送SET_CORE_SETTINGS訊息.bindApplication方法的主要功能是依次向主執行緒傳送訊息H.SET_CORE_SETTINGS
和H.BIND_APPLICATION
. 接下來再來說說這兩個訊息的處理過程
3.12 H.SET_CORE_SETTINGS
[-> ActivityThread.java ::H]
當主執行緒收到H.SET_CORE_SETTINGS,則呼叫handleSetCoreSettings
private void handleSetCoreSettings(Bundle coreSettings) { synchronized (mResourcesManager) { mCoreSettings = coreSettings; } onCoreSettingsChange(); }private void onCoreSettingsChange() { boolean debugViewAttributes = mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0; if (debugViewAttributes != View.mDebugViewAttributes) { View.mDebugViewAttributes = debugViewAttributes; // 由於發生改變, 請求所有的activities重啟啟動 for (Map.Entryentry : mActivities.entrySet()) { requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false); } } }
3.13 H.BIND_APPLICATION
[-> ActivityThread.java ::H]
當主執行緒收到H.BIND_APPLICATION,則呼叫handleBindApplication
private void handleBindApplication(AppBindData data) { mBoundApplication = data; mConfiguration = new Configuration(data.config); mCompatConfiguration = new Configuration(data.config); ... //設定程式名, 也就是說程式名是在程式真正建立以後的BIND_APPLICATION過程中才取名 Process.setArgV0(data.processName); android.ddm.DdmHandleAppName.setAppName(data.processName, UserHandle.myUserId()); if (data.persistent) { //低記憶體裝置, persistent程式不採用硬體加速繪製,以節省記憶體使用量 if (!ActivityManager.isHighEndGfx()) { HardwareRenderer.disable(false); } } //重置時區 TimeZone.setDefault(null); Locale.setDefault(data.config.locale); //更新系統配置 mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo); mCurDefaultDisplayDpi = data.config.densityDpi; applyCompatConfiguration(mCurDefaultDisplayDpi); data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); ... // 建立ContextImpl上下文 final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); if (!Process.isIsolated()) { final File cacheDir = appContext.getCacheDir(); if (cacheDir != null) { System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath()); } //用於儲存產生/編譯的圖形程式碼 final File codeCacheDir = appContext.getCodeCacheDir(); if (codeCacheDir != null) { setupGraphicsSupport(data.info, codeCacheDir); } } final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24)); DateFormat.set24HourTimePref(is24Hr); View.mDebugViewAttributes = mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0; ... //當處於除錯模式,則執行應用生成systrace資訊 boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0; Trace.setAppTracingAllowed(appTracingAllowed); //初始化 預設的http代理 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); if (b != null) { IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); final ProxyInfo proxyInfo = service.getProxyForNetwork(null); Proxy.setHttpProxySystemProperty(proxyInfo); } if (data.instrumentationName != null) { InstrumentationInfo ii = null; ii = appContext.getPackageManager().getInstrumentationInfo(data.instrumentationName, 0); mInstrumentationPackageName = ii.packageName; mInstrumentationAppDir = ii.sourceDir; mInstrumentationSplitAppDirs = ii.splitSourceDirs; mInstrumentationLibDir = ii.nativeLibraryDir; mInstrumentedAppDir = data.info.getAppDir(); mInstrumentedSplitAppDirs = data.info.getSplitAppDirs(); mInstrumentedLibDir = data.info.getLibDir(); ApplicationInfo instrApp = new ApplicationInfo(); instrApp.packageName = ii.packageName; instrApp.sourceDir = ii.sourceDir; instrApp.publicSourceDir = ii.publicSourceDir; instrApp.splitSourceDirs = ii.splitSourceDirs; instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs; instrApp.dataDir = ii.dataDir; instrApp.nativeLibraryDir = ii.nativeLibraryDir; LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, appContext.getClassLoader(), false, true, false); ContextImpl instrContext = ContextImpl.createAppContext(this, pi); java.lang.ClassLoader cl = instrContext.getClassLoader(); mInstrumentation = (Instrumentation)cl.loadClass(data.instrumentationName.getClassName()).newInstance(); mInstrumentation.init(this, instrContext, appContext, new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher, data.instrumentationUiAutomationConnection); ... } else { mInstrumentation = new Instrumentation(); } //FLAG_LARGE_HEAP則清除記憶體增長上限 if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) { dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); } else { dalvik.system.VMRuntime.getRuntime().clampGrowthLimit(); } try { // 透過反射,建立目標應用Application物件,即在AndroidManifest.xml檔案定義的應用名 Application app = data.info.makeApplication(data.restrictedBackupMode, null); mInitialApplication = app; if (!data.restrictedBackupMode) { Listproviders = data.providers; if (providers != null) { installContentProviders(app, providers); mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); } } mInstrumentation.onCreate(data.instrumentationArgs); //呼叫Application.onCreate()回撥方法. mInstrumentation.callApplicationOnCreate(app); } finally { StrictMode.setThreadPolicy(savedPolicy); } }
小節: 到此程式啟動的全過程基本介紹完, 那接下來程式該往哪執行呢, 那就是要繼續看[見流程3.8] AMS.attachApplicationLocked.從[3.9 ~ 3.13] 只是介紹了bindApplication過程, 該方法之後便是元件啟動相關的內容,本文主要將程式相關內容, 元件的內容後續還會再進一步介紹.
四. 總結
本文首先介紹AMS的4個同名不同引數的方法startProcessLocked; 緊接著講述了四大元件與程式的關係, Activity, Service, ContentProvider, BroadcastReceiver這四大元件,在啟動的過程,當其所承載的程式不存在時需要先建立程式. 再然後進入重點以startProcessLocked以引線一路講解整個過程所遇到的核心方法. 在整個過程中有新建立的程式與system_server程式之間的互動過程 是透過binder進行通訊的, 這裡有兩條binder通道分別為AMP/AMN 和 ATP/ATN.
上圖便是一次完整的程式建立過程,app的任何元件需要有一個承載其執行的容器,那就是程式, 那麼程式的建立過程都是由系統程式system_server透過socket向zygote程式來請求fork()新程式, 當建立出來的app process與system_server程式之間的通訊便是透過binder IPC機制.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/75/viewspace-2809443/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android 啟動過程簡析(一)之 init 程式Android
- Android應用程式程式啟動過程Android
- 【Android】【init】解析init程式啟動過程Android
- Android效能優化之啟動過程(冷啟動和熱啟動)Android優化
- Android App啟動過程AndroidAPP
- 深入理解ORACLE啟動過程Oracle
- Android系統啟動流程(三)解析SyetemServer程式啟動過程AndroidServer
- Android 核心分析 之八------Android 啟動過程詳解Android
- Oracle-解析啟動的全過程Oracle
- 深入理解linux啟動過程Linux
- Android Service的啟動過程Android
- Android Activity的啟動過程Android
- Android啟動過程深入解析Android
- Android 系統啟動過程Android
- Android應用程式啟動過程原始碼分析Android原始碼
- React Native Android 原始碼分析之啟動過程React NativeAndroid原始碼
- 安卓平臺Flutter啟動過程全解析安卓Flutter
- 深入理解 iOS App 的啟動過程iOSAPP
- 深入理解Linux啟動過程薦Linux
- Android系統啟動過程剖析Android
- Android中Activity啟動過程探究Android
- Android啟動過程剖析-深入淺出Android
- 【Android原始碼】Service的啟動過程Android原始碼
- 淺析Android Activity的啟動過程Android
- 原始碼|HDFS之NameNode:啟動過程原始碼
- 原始碼|HDFS之DataNode:啟動過程原始碼
- Android系統程式Zygote啟動過程的原始碼分析(3)AndroidGo原始碼
- Android啟動過程-萬字長文(Android14)Android
- 框架層理解Activity生命週期(APP啟動過程)框架APP
- 深入理解Android 之 Activity啟動流程(Android 10)Android
- 走進Linux之systemd啟動過程Linux
- Android系統啟動流程(四)Launcher啟動過程與系統啟動流程Android
- Windows 啟動過程Windows
- App 啟動過程(含 Activity 啟動過程) | 安卓 offer 收割基APP安卓
- Linux的啟動過程及init程式Linux
- Android系統原始碼分析--Activity啟動過程Android原始碼
- Android系統原始碼分析--Process啟動過程Android原始碼
- 剖析Linux系統啟動的後臺全過程 (zt)Linux