Android 程序在系统中如何完成启动
Posted yuminfeng728
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 程序在系统中如何完成启动相关的知识,希望对你有一定的参考价值。
一段程序的调用都有它的程序入口,众所周知Java程序的入口在main方法。作为android来说应用程序的启动是通过 ActivityThread 类 来执行的。系统中对于该类的介绍如下:
该类是管理应用程序进程中主线程的执行,调度和执行活动,广播以及活动管理者请求的其他操作。
当我打开App时,首先调用的是这个类中的main方法,也就是说这里控制着程序的启动。
ActivityThread#main
public static void main(String[] args)
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
//初始化当前的可访问环境,主要是系统内部的可存储环境
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// 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>");
//step 1:
Looper.prepareMainLooper();
//step 2:
ActivityThread thread = new ActivityThread();
thread.attach(false);
//初始化一个线程安全的handler对象
if (sMainThreadHandler == null)
sMainThreadHandler = thread.getHandler();
if (false)
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//执行消息队列,不断轮询消息。
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
main方法中重要的操作:
step 1:
Looper.prepareMainLooper() :初始化当前的线程作为一个looper,并且标记为应用中的main looper。后面还跟着对应的loop(),在消息队列中轮询接收的消息。
step 2:
实例化当前ActivityThread对象,并且调用attach。继续分析该方法中的调用。
ActivityThread#attach
private void attach(boolean system)
sCurrentActivityThread = this;
mSystemThread = system;
if (!system)
ViewRootImpl.addFirstDrawHandler(new Runnable()
@Override
public void run()
ensureJitEnabled();
);
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//step 1: 将ActivityManagerService 和 ApplicationThread 关联起来
final IActivityManager mgr = ActivityManager.getService();
try
mgr.attachApplication(mAppThread);
catch (RemoteException ex)
throw ex.rethrowFromSystemServer();
// Watch for getting close to heap limit.
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)
throw e.rethrowFromSystemServer();
);
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 libcore
DropBox.setReporter(new DropBoxReporter());
ViewRootImpl.ConfigChangedCallback configChangedCallback
= (Configuration globalConfig) ->
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(globalConfig,
null /* compat */))
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
// This actually changed the resources! Tell everyone about it.
if (mPendingConfiguration == null
|| mPendingConfiguration.isOtherSeqNewer(globalConfig))
mPendingConfiguration = globalConfig;
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
;
// 添加配置信息接口回调
ViewRootImpl.addConfigCallback(configChangedCallback);
上面方法中传入的参数为false,所以执行的是if中的逻辑。这里面主要的操作就是通过ActivityManager.getService() 返回了ActivityManagerService对象,然后调用attachApplication方法将ApplicationThread 对象关联。下面我们继续进入attachApplication 方法来分析。
ActivityManagerService#attachApplication
@Override
public final void attachApplication(IApplicationThread thread)
synchronized (this)
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
ActivityManagerService#attachApplicationLocked
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid)
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
// step 1: 记录正在运行的进程的详细信息
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0)
synchronized (mPidsSelfLocked)
app = mPidsSelfLocked.get(pid);
else
app = null;
//未找到对应pid的进程信息时,杀死该进程或者退出该ApplicationThread
if (app == null)
Slog.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID)
killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
else
try
thread.scheduleExit();
catch (Exception e)
// Ignore exceptions.
return false;
// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null)
handleAppDiedLocked(app, true, true);
// Tell the process all about itself.
if (DEBUG_ALL) Slog.v(
TAG, "Binding process pid " + pid + " to record " + app);
// 初始化 ProcessRecord 类中基本信息,来保存当前的一些状态
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;
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
app.killedByAm = false;
app.killed = false;
// We carefully use the same state that PackageManager uses for
// filtering, since we use this flag to decide if we need to install
// providers when user is unlocked later
app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
if (providers != null && checkAppInLaunchingProvidersLocked(app))
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
checkTime(startTime, "attachApplicationLocked: before bindApplication");
if (!normalMode)
Slog.i(TAG, "Launching preboot mode app: " + app);
if (DEBUG_ALL) Slog.v(
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
try
int testMode = ApplicationThreadConstants.DEBUG_OFF;
if (mDebugApp != null && mDebugApp.equals(processName))
testMode = mWaitForDebugger
? ApplicationThreadConstants.DEBUG_WAIT
: ApplicationThreadConstants.DEBUG_ON;
app.debugging = true;
if (mDebugTransient)
mDebugApp = mOrigDebugApp;
mWaitForDebugger = mOrigWaitForDebugger;
String profileFile = app.instr != null ? app.instr.mProfileFile : null;
ParcelFileDescriptor profileFd = null;
int samplingInterval = 0;
boolean profileAutoStop = false;
boolean profileStreamingOutput = false;
if (mProfileApp != null && mProfileApp.equals(processName))
mProfileProc = app;
profileFile = mProfileFile;
profileFd = mProfileFd;
samplingInterval = mSamplingInterval;
profileAutoStop = mAutoStopProfiler;
profileStreamingOutput = mStreamingOutput;
boolean enableTrackAllocation = false;
if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName))
enableTrackAllocation = true;
mTrackAllocationApp = null;
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName))
isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
&& ((mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
if (app.instr != null)
notifyPackageUse(app.instr.mClass.getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
+ processName + " with config " + getGlobalConfiguration());
ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
if (profileFd != null)
profileFd = profileFd.dup();
ProfilerInfo profilerInfo = profileFile == null ? null
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop,
profileStreamingOutput);
// We deprecated Build.SERIAL and it is not accessible to
// apps that target the v2 security sandbox. Since access to
// the serial is now behind a permission we push down the value.
String buildSerial = Build.UNKNOWN;
if (appInfo.targetSandboxVersion != 2)
buildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
.getSerial();
// Check if this is a secondary process that should be incorporated into some
// currently active instrumentation. (Note we do this AFTER all of the profiling
// stuff above because profiling can currently happen only in the primary
// instrumentation process.)
if (mActiveInstrumentation.size() > 0 && app.instr == null)
for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--)
ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid)
if (aInstr.mTargetProcesses.length == 0)
// This is the wildcard mode, where every process brought up for
// the target instrumentation should be included.
if (aInstr.mTargetInfo.packageName.equals(app.info.packageName))
app.instr = aInstr;
aInstr.mRunningProcesses.add(app);
else
for (String proc : aInstr.mTargetProcesses)
if (proc.equals(app.processName))
app.instr = aInstr;
aInstr.mRunningProcesses.add(app);
break;
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
if (app.instr != null)
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
else
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
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.wtf(TAG, "Exception thrown during bind of " + app, e);
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
startProcessLocked(app, "bind fail", processName);
return false;
// Remove this record from the list of starting applications.
mPersistentStartingProcesses.remove(app);
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
"Attach application locked removing on hold: " + app);
mProcessesOnHold.remove(app);
boolean badApp = false;
boolean didSomething = false;
// See if the top visible activity is waiting to run in this process...
// step2 : 顶部可见的活动等待启动
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);
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
catch (Exception e)
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid))
try
didSomething |= sendPendingBroadcastsLocked(app);
checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
catch (Exception e)
// If the app died trying to launch the receiver we declare it 'bad'
Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
badApp = true;
// Check whether the next backup agent is in this process...
if (!badApp && mBackupTarget != null && mBackupTarget.app == app)
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
"New app is backup target, launching agent for " + app);
notifyPackageUse(mBackupTarget.appInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
try
thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
mBackupTarget.backupMode);
catch (Exception e)
Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
badApp = true;
if (badApp)
app.kill("error during init", true);
handleAppDiedLocked(app, false, true);
return false;
if (!didSomething)
updateOomAdjLocked();
checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
return true;
上面的方法中,首先使用了ProcessRecord记录了进程中的一些信息,让后将ProcessRecord 与 ActivityStackSupervisor 关联起来,通过ActivityStackSupervisor可以运行所有的活动栈。
ActivityStackSupervisor#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 (!isFocusedStack(stack))
continue;
//step 1:检查当前活动是否应该被显示
ActivityRecord hr = stack.topRunningActivityLocked();
if (hr != null)
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName))
try
//step 2:
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, !PRESERVE_WINDOWS);
return didSomething;
遍历活动栈后,首先执行方法topRunningActivityLocked,然后找出当前线程匹配的活动执行realStartActivityLocked方法。
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException
if (!allPausedActivitiesComplete())
// While there are activities pausing we skipping starting any new activities until
// pauses are complete. NOTE: that we also do this for activities that are starting in
// the paused state because they will first be resumed then paused on the client side.
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"realStartActivityLocked: Skipping start of r=" + r
+ " some activities pausing...");
return false;
r.startFreezingScreenLocked(app, 0);
if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */, true /* isTop */))
// We only set the visibility to true if the activity is allowed to be visible based on
// keyguard state. This avoids setting this into motion in window manager that is later
// cancelled due to later calls to ensure visible activities that set visibility back to
// false.
r.setVisibility(true);
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
// Have the window manager re-evaluate the orientation of the screen based on the new
// activity order. Note that as a result of this, it can call back into the activity
// manager with a new orientation. We don't care about that, because the activity is not
// currently running so we are just restarting it anyway.
if (checkConfig)
final int displayId = r.getDisplayId();
final Configuration config = mWindowManager.updateOrientationFromAppTokens(
getDisplayOverrideConfiguration(displayId),
r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId);
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring
// configurations and trying to resume top activity of focused stack.
mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */,
displayId);
if (mKeyguardController.isKeyguardLocked())
r.notifyUnknownVisibilityLaunched();
final int applicationInfoUid =
(r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid))
Slog.wtf(TAG,
"User ID for activity changing for " + r
+ " appInfo.uid=" + r.appInfo.uid
+ " info.ai.uid=" + applicationInfoUid
+ " old=" + r.app + " new=" + app);
r.app = app;
app.waitingToKill = null;
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
int idx = app.activities.indexOf(r);
if (idx < 0)
app.activities.add(r);
mService.updateLruProcessLocked(app, true, null);
mService.updateOomAdjLocked();
final TaskRecord task = r.getTask();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV)
setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
final ActivityStack stack = task.getStack();
try
if (app.thread == null)
throw new RemoteException();
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume)
// We don't need to deliver new intents and/or set results if activity is going
// to pause immediately after launch.
results = r.results;
newIntents = r.newIntents;
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Launching: " + r + " icicle=" + r.icicle + " with results=" + results
+ " newIntents=" + newIntents + " andResume=" + andResume);
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId,
System.identityHashCode(r), task.taskId, r.shortComponentName);
if (r.isHomeActivity())
// Home process is the root process of the task.
mService.mHomeProcess = task.mActivities.get(0).app;
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
r.sleeping = false;
r.forceNewConfig = false;
mService.showUnsupportedZoomDialogIfNeededLocked(r);
mService.showAskCompatModeDialogLocked(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
ProfilerInfo profilerInfo = null;
if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName))
if (mService.mProfileProc == null || mService.mProfileProc == app)
mService.mProfileProc = app;
final String profileFile = mService.mProfileFile;
if (profileFile != null)
ParcelFileDescriptor profileFd = mService.mProfileFd;
if (profileFd != null)
try
profileFd = profileFd.dup();
catch (IOException e)
if (profileFd != null)
try
profileFd.close();
catch (IOException o)
profileFd = null;
profilerInfo = new ProfilerInfo(profileFile, profileFd,
mService.mSamplingInterval, mService.mAutoStopProfiler,
mService.mStreamingOutput);
app.hasShownUi = true;
app.pendingUiClean = true;
app.forceProcessStateUpTo(mService.mTopProcessState);
// Because we could be starting an Activity in the system process this may not go across
// a Binder interface which would create a new Configuration. Consequently we have to
// always create a new Configuration here.
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global and
// override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0)
// This may be a heavy-weight process! Note that the package
// manager will ensure that only activity can run in the main
// process of the .apk, which is the only thing that will be
// considered heavy-weight.
if (app.processName.equals(app.info.packageName))
if (mService.mHeavyWeightProcess != null
&& mService.mHeavyWeightProcess != app)
Slog.w(TAG, "Starting new heavy weight process " + app
+ " when already running "
+ mService.mHeavyWeightProcess);
mService.mHeavyWeightProcess = app;
Message msg = mService.mHandler.obtainMessage(
ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
msg.obj = r;
mService.mHandler.sendMessage(msg);
catch (RemoteException e)
if (r.launchFailed)
// This is the second time we failed -- finish activity
// and give up.
Slog.e(TAG, "Second failure launching "
+ r.intent.getComponent().flattenToShortString()
+ ", giving up", e);
mService.appDiedLocked(app);
stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"2nd-crash", false);
return false;
// This is the first time we failed -- restart process and
// retry.
r.launchFailed = true;
app.activities.remove(r);
throw e;
r.launchFailed = false;
if (stack.updateLRUListLocked(r))
Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
if (andResume)
// As part of the process of launching, ActivityThread also performs
// a resume.
stack.minimalResumeActivityLocked(r);
else
// This activity is not starting in the resumed state... which should look like we asked
// it to pause+stop (but remain visible), and it has done so and reported back the
// current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to PAUSED: " + r + " (starting in paused state)");
r.state = PAUSED;
// Launch the new version setup screen if needed. We do this -after-
// launching the initial activity (that is, home), so that it can have
// a chance to initialize itself while in the background, making the
// switch back to it faster and look better.
if (isFocusedStack(stack))
mService.startSetupActivityLocked();
// Update any services we are bound to that might care about whether
// their client may have activities.
if (r.app != null)
mService.mServices.updateServiceConnectionActivitiesLocked(r.app);
return true;
通过这个方法中完成了一些启动Activity的准备工作,然后调用scheduleLaunchActivity方法,从上面我们可以知道这里调用的是ApplicationThread中的方法:
ActivityThread.ApplicationThread#scheduleLaunchActivity
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo)
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
在这里我们可以看到调用的是Handler的消息通信机制,当Activity状态改变时,都会有对应的一个消息发送出去。而且我们还看到ApplicationThread类中包含了许多不同的scheduleXXX 类的方法,这些方法代表了不同启动状态,每个状态的改变都通过它来发送给Handler进行处理。
public void handleMessage(Message msg)
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what)
case LAUNCH_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case RELAUNCH_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PAUSE_ACTIVITY_FINISHING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, true, (args.argi1 & USER_LEAVING) != 0,
args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
....
由此我们可以得出一个结论,Application运行过程中,对于Activity的操作状态转变,都是通过Handler消息机制来完成的。而这个消息队列就是在ActivityThread中main方法里面轮询的。
以上是关于Android 程序在系统中如何完成启动的主要内容,如果未能解决你的问题,请参考以下文章