参考:https://www.jianshu.com/p/89fd44083c1c
回到之前的startspecificActivityLocked方法
一:从ActivityStackSupervisor到ActivityManagerService
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
getLaunchTimeTracker().setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
此处判断activit所在进程是否已经启动,如果还没有启动的话,则启动之
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
@GuardedBy("this")
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 */);
}
@GuardedBy("this")
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) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
checkTime(startTime, "startProcess: after getProcessRecord");
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
if (mAppErrors.isBadProcessLocked(info)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + info.processName);
return null;
}
} else {
// When the user is explicitly starting a process, then clear its
// crash count so that we won't make it bad until they see at
// least one crash dialog again, and make the process good again
// if it had been bad.
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + info.processName);
mAppErrors.resetProcessCrashTimeLocked(info);
if (mAppErrors.isBadProcessLocked(info)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
mAppErrors.clearBadProcessLocked(info);
if (app != null) {
app.bad = false;
}
}
}
} else {
// If this is an isolated process, it can't re-use an existing process.
app = null;
}
// We don't have to do anything more if:
// (1) There is an existing application record; and
// (2) The caller doesn't think it is dead, OR there is no thread
// object attached to it so we know it couldn't have crashed; and
// (3) There is a pid assigned to it, so it is either starting or
// already running.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
if (app != null && app.pid > 0) {
if ((!knownToBeDead && !app.killed) || app.thread == null) {
// We already have the app running, or are waiting for it to
// come up (we have a pid but not yet its thread), so keep it.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: done, added package to proc");
return app;
}
// An application record is attached to a previous process,
// clean it up now.
if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
checkTime(startTime, "startProcess: bad proc running, killing");
killProcessGroup(app.uid, app.pid);
handleAppDiedLocked(app, true, true);
checkTime(startTime, "startProcess: done killing old proc");
}
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
if (app == null) {
checkTime(startTime, "startProcess: creating new process record");
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
return null;
}
app.crashHandler = crashHandler;
app.isolatedEntryPoint = entryPoint;
app.isolatedEntryPointArgs = entryPointArgs;
checkTime(startTime, "startProcess: done creating new process record");
} else {
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: added package to existing proc");
}
// If the system is not ready yet, then hold off on starting this
// process until it is.
if (!mProcessesReady
&& !isAllowedWhileBooting(info)
&& !allowWhileBooting) {
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
"System not ready, putting on hold: " + app);
checkTime(startTime, "startProcess: returning with proc on hold");
return app;
}
checkTime(startTime, "startProcess: stepping in to startProcess");
final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
checkTime(startTime, "startProcess: done starting proc!");
return success ? app : null;
}
下面是多个startProcessLocked 调用
在最后一个startProcessLocked,有这么一句
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
requiredAbi, instructionSet, invokeWith, app.startTime);
private ProcessStartResult startProcess(String hostingType, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
final ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
checkTime(startTime, "startProcess: returned from zygote!");
return startResult;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
二:从ActivityManagerService到Process
从前面的Process.start方法,最终来到了Process类
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
三Process到ZygoteProcess
继续点进去start方法内
/**
* Start a new process.
*
* <p>If processes are enabled, a new process is created and the
* static main() function of a <var>processClass</var> is executed there.
* The process will continue running after this function returns.
*
* <p>If processes are not enabled, a new thread in the caller's
* process is created and main() of <var>processclass</var> called there.
*
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass. This allows you to
* make easily identifyable processes even if you are using the same base
* <var>processClass</var> to start them.
*
* When invokeWith is not null, the process will be started as a fresh app
* and not a zygote fork. Note that this is only allowed for uid 0 or when
* runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
*
* @param processClass The class to use as the process's main entry
* point.
* @param niceName A more readable name to use for the process.
* @param uid The user-id under which the process will run.
* @param gid The group-id under which the process will run.
* @param gids Additional group-ids associated with the process.
* @param runtimeFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi non-null the ABI this app should be started with.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*/
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
startViaZygote方法
/**
* Starts a new process via the zygote mechanism.
*
* @param processClass Class name whose static main() to run
* @param niceName 'nice' process name to appear in ps
* @param uid a POSIX uid that the new process should setuid() to
* @param gid a POSIX gid that the new process shuold setgid() to
* @param gids null-ok; a list of supplementary group IDs that the
* new process should setgroup() to.
* @param runtimeFlags Additional flags for the runtime.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi the ABI the process should use.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param startChildZygote Start a sub-zygote. This creates a new zygote process
* that has its state cloned from this zygote process.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
boolean startChildZygote,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
openZygoteSocketIfNeeded
/**
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry. Requires that mLock be held.
*/
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
/**
* Sends an argument list to the zygote process, which starts a new child
* and returns the child's pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
*
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
@GuardedBy("mLock")
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
// Throw early if any of the arguments are malformed. This means we can
// avoid writing a partial response to the zygote.
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
/**
* See com.android.internal.os.SystemZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
// Should there be a timeout on this?
Process.ProcessStartResult result = new Process.ProcessStartResult();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
最终是fork出来了一个进程。。
四:ActivityThread
最后是通过反射的方式调用了ActivityThread的main方法
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// 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>");
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
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");
}