編輯:Android資訊
Android系統將進程做得很友好的封裝,對於上層app開發者來說進程幾乎是透明的. 了解Android的朋友,一定知道Android四大組件,但對於進程可能會相對較陌生. 一個進程裡面可以跑多個app(通過share uid的方式), 一個app也可以跑在多個進程裡(通過配置Android:process屬性).
再進一步進程是如何創建的, 可能很多人不知道fork的存在. 在我的文章理解Android進程創建流程 集中一點詳細介紹了Process.start
的過程是如何一步步創建進程.本文則是從另個角度來全局性講解Android進程啟動全過程所涉及的根脈, 先來看看AMS.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 */); }
小結:
Activity, Service, ContentProvider, BroadcastReceiver這四大組件,在啟動的過程,當其所承載的進程不存在時需要先創建進程. 這個創建進程的過程是調用前面講到的startProcessLocked方法1(a) . 調用流程: 1(a) => 1(b) ==> 2(b). 下面再簡單說說這4大組件與進程創建是在何時需要創建的.
啟動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); }
啟動服務過程: 調用startService,該方法經過層層調用,最終會調用ActiveServices.java中的bringUpServiceLocked
,當Service進程沒有啟動的情況(app==null), 則需要創建相應的進程. 更多關於Service, 見startService流程分析
[-> 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) { ... } } ... }
ContentProvider處理過程: 調用ContentResolver.query該方法經過層層調用, 最終會調用到AMS.java中的getContentProviderImpl
,當ContentProvider所對應進程不存在,則需要創建新進程. 更多關於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); } ... }
廣播處理過程: 調用sendBroadcast,該方法經過層層調用, 最終會調用到BroadcastQueue.java中的processNextBroadcast
,當BroadcastReceiver所對應的進程尚未啟動,則創建相應進程. 更多關於broadcast, 見Android 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) { ... } ... }
Activity, Service, ContentProvider, BroadcastReceiver這四大組件在啟動時,當所承載的進程不存在時,都需要創建. 進程的創建過程交由系統進程system_server來完成的.
簡稱:
圖解:
startProcessLocked
方法,該方法最終通過socket方式,將需要創建新進程的消息告知Zygote進程,並阻塞等待Socket返回新創建進程的pid;system_server擁有ATP/AMS, 每一個新創建的進程都會有一個相應的AT/AMS,從而可以跨進程 進行相互通信. 這便是進程創建過程的完整生態鏈.
四大組件的進程創建時機:
前面剛已介紹四大組件的創建進程的過程是調用1(a) startProcessLocked
方法,該方法會再調用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) { 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; }
主要功能:
另外, 進程的uid是在進程真正創建之前調用newProcessRecordLocked
方法來獲取的uid, 這裡會考慮是否為isolated的情況.
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 } }
關於Process.start()是通過socket通信告知Zygote創建fork子進程,創建新進程後將ActivityThread類加載到新進程,並調用ActivityThread.main()方法。詳細過程見理解Android進程創建流程,接下來進入AT.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("<pre-initialized>"); //創建主線程的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"); }
thread = new ActivityThread()
: 該過程會初始化幾個很重要的變量:
H
繼承於Handler
;用於處理組件的生命周期.mH
,這就是主線程的handler對象.之後主線程調用Looper.loop(),進入消息循環狀態, 當沒有消息時主線程進入休眠狀態, 一旦有消息到來則喚醒主線程並執行相關操作.
[-> 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("<pre-initialized>", 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的處理流程:
ApplicationThread
[-> 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”
[-> 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; } } }
[-> 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對象進行通信.
[-> 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); List<ProviderInfo> providers = 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; }
下面,再來說說thread.bindApplication的過程.
[-> ApplicationThreadNative.java ::ApplicationThreadProxy]
class ApplicationThreadProxy implements IApplicationThread { ... public final void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo, Bundle testArgs, IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection, int debugMode, boolean openGlTrace, boolean restrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> 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過程.
[-> 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); List<ProviderInfo> providers = 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<String, IBinder> 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; } ... }
[-> ActivityThread.java ::ApplicationThread]
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) { //將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
. 接下來再來說說這兩個消息的處理過程
[-> 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.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) { requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false); } } }
[-> 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) { List<ProviderInfo> providers = 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機制.
關於Android程序的構架, 當前(2016.10)最流行的模式即為MVP模式, Google官方提供了Sample代碼來展示這種模式的用法. Repo地址:
本文由碼農網 – 楊小勇原創,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! Android總體有五大布局: 線性布局(LiearLayout)
昨天,一位認證信息為小米員工的網友在微博上發言,“iPhone 6 用戶都不在意 1G 內存不夠,紅米 2 的 1G 內存夠用了,保持流暢的秘訣就是少裝 App.
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! 本文將介紹一種有效改變Android按鈕顏色的方法。 按鈕可以在狀