本代码基于android sdk 28
//com/android/server/SystemServer.java
private void run() {
try {
traceBeginAndSlog("InitBeforeStartServices");
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it shortly.
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
//
// Default the timezone property to GMT if not set.
//
String timezoneProperty = SystemProperties.get("persist.sys.timezone");
if (timezoneProperty == null || timezoneProperty.isEmpty()) {
Slog.w(TAG, "Timezone not set; setting to GMT.");
SystemProperties.set("persist.sys.timezone", "GMT");
}
// If the system has "persist.sys.language" and friends set, replace them with
// "persist.sys.locale". Note that the default locale at this point is calculated
// using the "-Duser.locale" command line flag. That flag is usually populated by
// AndroidRuntime using the same set of system properties, but only the system_server
// and system apps are allowed to set them.
//
// NOTE: Most changes made here will need an equivalent change to
// core/jni/AndroidRuntime.cpp
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// The system server should never make non-oneway calls
Binder.setWarnOnBlocking(true);
// The system server should always load safe labels
PackageItemInfo.setForceSafeLabels(true);
// Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
SQLiteCompatibilityWalFlags.init(null);
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
int uptimeMillis = (int) SystemClock.elapsedRealtime();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
if (!mRuntimeRestart) {
MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
}
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
// property so that it is in sync. We can | xq oqi't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Mmmmmm... more memory!
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
// Within the system server, any incoming Bundles should be defused
// to avoid throwing BadParcelableException.
BaseBundle.setShouldDefuse(true);
// Within the system server, when parceling exceptions, include the stack trace
Parcel.setStackTraceParceling(true);
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
// Increase the number of binder threads in system_server
BinderInternal.setMaxThreads(sMaxBinderThreads);
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
Looper.getMainLooper().setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
// Initialize native services.
//创建Looper消息
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
SystemServerInitThreadPool.get();
} finally {
traceEnd(); // InitBeforeStartServices
}
// Start services.
try {
traceBeginAndSlog("StartServices");
//启动引导服务
startBootstrapServices();
//启动核心服务
startCoreServices();
//启动其他服务
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
StrictMode.initVmDefaults(null);
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
int uptimeMillis = (int) SystemClock.elapsedRealtime();
MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
final int MAX_UPTIME_MILLIS = 60 * 1000;
if (uptimeMillis > MAX_UPTIME_MILLIS) {
Slog.wtf(SYSTEM_SERVER_TIMING_TAG,
"SystemServer init took too long. uptimeMillis=" + uptimeMillis);
}
}
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
//com/android/server/SystemServer.java
private void startBootstrapServices() {
Slog.i(TAG, "Reading configuration...");
final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig";
traceBeginAndSlog(TAG_SYSTEM_CONFIG);
SystemServerInitThreadPool.get().submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG);
traceEnd();
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
traceBeginAndSlog("StartInstaller");
Installer installer = mSystemServiceManager.startService(Installer.class);
traceEnd();
// In some cases after launching an app we need to access device identifiers,
// therefore register the device identifier policy before the activity manager.
traceBeginAndSlog("DeviceIdentifiersPolicyService");
mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
traceEnd();
// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
//设置AMS系统服务管理器
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
//设置AMS中app的安装器
mActivityManagerService.setInstaller(installer);
traceEnd();
// Power manager needs to be started early because other services need it.
// Native daemons may be watching for it to be registered so it must be ready
// to handle incoming binder calls immediately (including being able to verify
// the permissions for those calls).
traceBeginAndSlog("StartPowerManager");
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
traceEnd();
// Now that the power manager has been started, let the activity manager
// initialize power management features.
traceBeginAndSlog("InitPowerManagement");
mActivityManagerService.initPowerManagement();
traceEnd();
// Bring up recovery system in case a rescue party needs a reboot
traceBeginAndSlog("StartRecoverySystemService");
mSystemServiceManager.startService(RecoverySystemService.class);
traceEnd();
// Now that we have the bare essentials of the OS up and running, take
// note that we just booted, which might send out a rescue party if
// we're stuck in a runtime restart loop.
RescueParty.noteBoot(mSystemContext);
// Manages LEDs and display backlight so we need it to bring up the display.
traceBeginAndSlog("StartLightsService");
mSystemServiceManager.startService(LightsService.class);
traceEnd();
traceBeginAndSlog("StartSidekickService");
// Package manager isn't started yet; need to use SysProp not hardware feature
if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) {
mSystemServiceManager.startService(WEAR_SIDEKICK_SERVICE_CLASS);
}
traceEnd();
// Display manager is needed to provide display metrics before package manager
// starts up.
traceBeginAndSlog("StartDisplayManager");
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
traceEnd();
// We need the default display before we can initialize the package manager.
traceBeginAndSlog("WaitForDisplay");
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
traceEnd();
// Only run "core" apps if we're encrypting the device.
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
// Start the package manager.
if (!mRuntimeRestart) {
MetricsLogger.histogram(null, "boot_package_manager_init_start",
(int) SystemClock.elapsedRealtime());
}
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
traceEnd();
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
MetricsLogger.histogram(null, "boot_package_manager_init_ready",
(int) SystemClock.elapsedRealtime());
}
// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
// Note: this isn't needed during decryption (we don't have /data anyways).
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
traceBeginAndSlog("StartOtaDexOptService");
try {
OtaDexoptService.main(mSystemContext, mPackageManagerService);
} catch (Throwable e) {
reportWtf("starting OtaDexOptService", e);
} finally {
traceEnd();
}
}
}
traceBeginAndSlog("StartUserManagerService");
mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
traceEnd();
// Initialize attribute cache used to cache resources from packages.
traceBeginAndSlog("InitAttributerCache");
AttributeCache.init(mSystemContext);
traceEnd();
// Set up the Application instance for the system process and get started.
traceBeginAndSlog("SetSystemProcess");
//设置SystemServe
mActivityManagerService.setSystemProcess();
traceEnd();
// DisplayManagerService needs to setup android.display scheduling related policies
// since setSystemProcess() would have overridden policies due to setProcessGroup
mDisplayManagerService.setupSchedulerPolicies();
// Manages Overlay packages
traceBeginAndSlog("StartOverlayManagerService");
mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
traceEnd();
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
// Start sensor service in a separate thread. Completion should be checked
// before using it.
mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
TimingsTraceLog traceLog = new TimingsTraceLog(
SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
traceLog.traceBegin(START_SENSOR_SERVICE);
startSensorService();
traceLog.traceEnd();
}, START_SENSOR_SERVICE);
}
//com/android/server/am/ActivityManagerService.java
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
public Lifecycle(Context context) {
super(context);
//真正创建AMS的fbyy
mService = new ActivityManagerService(context);
}
@Override
public void onStart() {
mService.start();
}
public ActivityManagerService getService() {
return mService;
}
}
//com/android/server/SystemServiceManager.java
public SystemService startService(String className) {
final Class<SystemService> serviceClass;
try {
serviceClass = (Class<SystemService>)Class.forName(className);
} catch (ClassNotFoundException ex) {
Slog.i(TAG, "Starting " + className);
throw new RuntimeException("Failed to create service " + className
+ ": service class not found, usually indicates that the caller should "
+ "have called PackageManager.hasSystemFeature() to check whether the "
+ "feature is available on this device before trying to start the "
+ "services that implement it", ex);
}
return startService(serviceClass);
}
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
//通过反射获取lifeCycle的对象。
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
public void startService(@NonNull final SystemService service) {
// Register it.//注册服务
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
//开启服务
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
//com/android/server/am/ActivityManagerService.java
public ActivityManagerService(Context systemContext) {
LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
mInjector = new Injector();
mContext = systemContext;
mFactoryTest = FactoryTest.getMode();
mSystemThread = ActivityThread.currentActivityThread();
mUiContext = mSystemThread.getSystemUiContext();
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
mPermissionReviewRequired = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_permissionReviewRequired);
//创建一个前台线程并获取mHandler
mHandlerThread = new ServiceThread(TAG,
THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
//创建一个UI线程,这个线程主要处理跟ams内部发出的需要进行ui处理的事件
mUiHandler = mInjector.getUiHandler(this);
mProcStartHandlerThread = new ServiceThread(TAG + ":procStart",
THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
mProcStartHandlerThread.start();
mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
mConstants = new ActivityManagerConstants(this, mHandler);
/* static; one-time init here */
if (sKillHandler == null) {
sKillThread = new ServiceThread(TAG + ":kill",
THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
sKillThread.start();
sKillHandler = new KillHandler(sKillThread.getLooper());
}
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
"background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
mServices = new ActiveServices(this);
mProviderMap = new ProviderMap(this);
mAppErrors = new AppErrors(mUiContext, this);
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
mAppWarnings = new AppWarnings(this, mUiContext, mHandler, mUiHandler, systemDir);
// TODO: Move creation of battery stats service outside of activity manager service.
mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
mAppOpsService = mInjector.getAppOpsService(new File(systemDir, "appops.xml"), mHandler);
mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
mUserController = new UserController(this);
mVrController = new VrController(this);
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) {
mUseFifoUiScheduling = true;
}
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
mStackSupervisor = createStackSupervisor();
mStackSupervisor.onConfigurationChanged(mTempConfig);
mKeyguardController = mStackSupervisor.getKeyguardController();
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mTaskChangeNotificationController =
new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
mActivityStartController = new ActivityStartController(this);
mRecentTasks = createRecentTasks();
mStackSupervisor.setRecentTasks(mRecentTasks);
mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
mLifecycleManager = new ClientLifecycleManager();
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
synchronized (mProcessCpuTracker) {
mProcessCpuInitLatch.countDown();
mProcessCpuTracker.init();
}
while (true) {
try {
try {
synchronized(this) {
final long now = SystemClock.uptimeMillis();
long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now;
long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
//Slog.i(TAG, "Cpu delay=" + nextCpuDelay
// + ", write delay=" + nextWriteDelay);
if (nextWriteDelay < nextCpuDelay) {
nextCpuDelay = nextWriteDelay;
}
if (nextCpuDelay > 0) {
mProcessCpuMutexFree.set(true);
this.wait(nextCpuDelay);
}
}
} catch (InterruptedException e) {
}
updateCpuStatsNow();
} catch (Exception e) {
Slog.e(TAG, "Unexpected exception collecting process stats", e);
}
}
}
};
mHiddenApiBlacklist = new HiddenApiSettings(mHandler, mContext);
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
// bind background thread to little cores
// this is expected to fail inside of framework tests because apps can't touch cpusets directly
// make sure we've already adjusted system_server's internal view of itself first
updateOomAdjLocked();
try {
Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
Process.THREAD_GROUP_BG_NONINTERACTIVE);
} catch (Exception e) {
Slog.w(TAG, "Setting background thread cpuset failed");
}
}
添加进程的相关服务,如meminfo,gfxinfo,dbinfo,cpuinfo等
方法的主要作用就是注册各种服务,framework-res.apk系统文件的初始化;因为framework-res.apk是一个apk文件,跟其它apk文件一样,它应该运行在一个进程中,而ams是负责进程管理和调度的,所以apk的进程在ams中是有一个对应的管理结构的,PrpcessRecord就是一个跟进程相关的类,ams中的变量mPidsSelfLocked就是 负责存储相关的进程。
//com/android/server/am/ActivityManagerService.java
public void setSystemProcess() {
try {
//将ams服务添加进ServiceManager服务中进行管理
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_HIGH);
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this),
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
//向pms查询package名为android的applicationInfo信息,其实这个是framework-res.apk
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
//该方法调用ContextImpl的installSystemApplicationInfo()方法,最终调用LoadedApk的
//installSystemApplicationInfo,加载名为“android”的package
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
//将运行环境和进程管理结构对应起来交给ams统一管理
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find android system package", e);
}
// Start watching app ops after we and the package manager are up and running.
mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null,
new IAppOpsCallback.Stub() {
@Override public void opChanged(int op, int uid, String packageName) {
if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
if (mAppOpsService.checkOperation(op, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
runInBackgroundDisabled(uid);
}
}
}
});
}
方法中启动了CameraService,AlarmManagerService,VrManagerService,AccountManagerService,VibratorService,MountService,NetworkManagementService,ConnectivityService,WindowManagerService,UsbService,SerialService,AudioService等.
这个阶段主要是做了系统provider的安装,发送PRE_BOOT_COMPLETED广播,杀掉procsTokill中的进程,杀掉进程且不允许重启,此时系统和进程都处于ready状态;在准备完毕后会启动一系列服务。
注意:源码中总共有1154行左右的代码,详情请看相关代码
启动了DropBoxManagerService(调试信息管理),BatteryService(电池电量管理),UsageStatsService(应用使用情况)以及WebViewUpdateService。core service 相对于BootStrap的优先级略低。
//com/android/server/SystemServer.java
private void startCoreServices() {
traceBeginAndSlog("StartBatteryService");
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
traceEnd();
// Tracks application usage stats.
traceBeginAndSlog("StartUsageService");
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
traceEnd();
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
traceBeginAndSlog("StartWebViewUpdateService");
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
traceEnd();
}
// Tracks cpu time spent in binder calls
traceBeginAndSlog("StartBinderCallsStatsService");
BinderCallsStatsService.start();
traceEnd();
}
现在ams环境已经准备好,然后我们就根据具体的应用启动流程对ams进行详细 的分析。
startActivity()
//android/app/Activity.java
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
//手动注意
startActivityForResult(intent, -1);
}
}
startActivityForResult
//android/app/Activity.java
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
//手动注意
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
execStartActivity
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
如上方法调用有十个参数,其详细含义。
//android/app/Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
//手动注意:Binder进程间通讯,最终调用到ams服务中。
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
//检查activity是否启动成功
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
startActivity
//com/android/server/am/ActivityManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivity");
userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here. 手动注意
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
*execute
//com/android/server/am/ActivityStarter.java
int execute() {
try {
// TODO(b/64750076): Look into passing request directly to these methods to allow
// for transactional diffs and preprocessing.
if (mRequest.mayWait) {
return startActivityMayWait(mRequest.caller, mRequest.callingUid,
mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup);
} else {
return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
mRequest.outActivity, mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup);
}
} finally {
onExecutionComplete();
}
}
startActivityMyWait
//com/android/server/am/ActivityStarter.java
private int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, WaitResult outResult,
Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
int userId, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
boolean componentSpecified = intent.getComponent() != null;
final int realCallingPid = Binder.getCallingPid();
final int realCallingUid = Binder.getCallingUid();
int callingPid;
if (callingUid >= 0) {
callingPid = -1;
} else if (caller == null) {
callingPid = realCallingPid;
callingUid = realCallingUid;
} else {
callingPid = callingUid = -1;
}
// Save a copy in case ephemeral needs it
final Intent ephemeralIntent = new Intent(intent);
// Don't modify the client's object! 创建新的Intent对象,即便intent被修改也不受影响
intent = new Intent(intent);
if (componentSpecified
&& !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)
&& !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& mService.getPackageManagerInternalLocked()
.isInstantAppInstallerComponent(intent.getComponent())) {
// intercept intents targeted directly to the ephemeral installer the
// ephemeral installer should never be started with a raw Intent; instead
// adjust the intent so it looks like a "normal" instant app launch
intent.setComponent(null /*component*/);
componentSpecified = false;
}
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
0 /* matchFlags */,
computeResolveFilterUid(
callingUid, realCallingUid, mRequest.filterCallingUid));
if (rInfo == null) {
UserInfo userInfo = mSupervisor.getUserInfo(userId);
if (userInfo != null && userInfo.isManagedProfile()) {
// Special case for managed profiles, if attempting to launch non-cryto aware
// app in a locked managed profile from an unlocked parent allow it to resolve
// as user will be sent via confirm credentials to unlock the profile.
UserManager userManager = UserManager.get(mService.mContext);
boolean profileLockedAndParentUnlockingOrUnlocked = false;
long token = Binder.clearCallingIdentity();
try {
UserInfo parent = userManager.getProfileParent(userId);
profileLockedAndParentUnlockingOrUnlocked = (parent != null)
&& userManager.isUserUnlockingOrUnlocked(parent.id)
&& !userManager.isUserUnlockingOrUnlocked(userId);
} finally {
Binder.restoreCallingIdentity(token);
}
if (profileLockedAndParentUnlockingOrUnlocked) {
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
computeResolveFilterUid(
callingUid, realCallingUid, mRequest.filterCallingUid));
}
}
}
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
synchronized (mService) {
final ActivityStack stack = mSupervisor.mFocusedStack;
stack.mConfigWillChange = globalConfig != null
&& mService.getGlobalConfiguration().diff(globalConfig) != 0;
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Starting activity when config will change = " + stack.mConfigWillChange);
final long origId = Binder.clearCallingIdentity();
if (aInfo != null &&
(aInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 &&
mService.mHasHeavyWeightFeature) {
// This may be a heavy-weight process! Check to see if we already
// have another, different heavy-weight process running.
if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
final ProcessRecord heavy = mService.mHeavyWeightProcess;
if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
|| !heavy.processName.equals(aInfo.processName))) {
int appCallingUid = callingUid;
if (caller != null) {
ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {
appCallingUid = callerApp.info.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
SafeActivityOptions.abort(options);
return ActivityManager.START_PERMISSION_DENIED;
}
}
IIntentSender target = mService.getIntentSenderLocked(
ActivityManager.INTENT_SENDER_ACTIVITY, "android",
appCallingUid, userId, null, null, 0, new Intent[] { intent },
new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT, null);
Intent newIntent = new Intent();
if (requestCode >= 0) {
// Caller is requesting a result.
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
}
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
new IntentSender(target));
if (heavy.activities.size() > 0) {
ActivityRecord hist = heavy.activities.get(0);
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
hist.packageName);
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
hist.getTask().taskId);
}
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
aInfo.packageName);
newIntent.setFlags(intent.getFlags());
newIntent.setClassName("android",
HeavyWeightSwitcherActivity.class.getName());
intent = newIntent;
resolvedType = null;
caller = null;
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
componentSpecified = true;
rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,
0 /* matchFlags */, computeResolveFilterUid(
callingUid, realCallingUid, mRequest.filterCallingUid));
aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
aInfo = mService.getActivityInfoForUser(aInfo, userId);
}
}
}
}
final ActivityRecord[] outRecord = new ActivityRecord[1];
//手动注意
int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
allowPendingRemoteAnimationRegistryLookup);
Binder.restoreCallingIdentity(origId);
if (stack.mConfigWillChange) {
// If the caller also wants to switch to a new configuration,
// do so now. This allows a clean switch, as we are waiting
// for the current activity to pause (so we will not destroy
// it), and have not yet started the next activity.
mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
stack.mConfigWillChange = false;
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Updating to new configuration after starting activity.");
mService.updateConfigurationLocked(globalConfig, null, false);
}
if (outResult != null) {
outResult.result = res;
final ActivityRecord r = outRecord[0];
switch(res) {
case START_SUCCESS: {
mSupervisor.mWaitingActivityLaunched.add(outResult);
do {
try {
mService.wait();
} catch (InterruptedException e) {
}
} while (outResult.result != START_TASK_TO_FRONT
&& !outResult.timeout && outResult.who == null);
if (outResult.result == START_TASK_TO_FRONT) {
res = START_TASK_TO_FRONT;
}
break;
}
case START_DELIVERED_TO_TOP: {
outResult.timeout = false;
outResult.who = r.realActivity;
outResult.totalTime = 0;
outResult.thisTime = 0;
break;
}
case START_TASK_TO_FRONT: {
// ActivityRecord may represent a different activity, but it should not be
// in the resumed state.
if (r.nowVisible && r.isState(RESUMED)) {
outResult.timeout = false;
outResult.who = r.realActivity;
outResult.totalTime = 0;
outResult.thisTime = 0;
} else {
outResult.thisTime = SystemClock.uptimeMillis();
mSupervisor.waitActivityVisible(r.realActivity, outResult);
// Note: the timeout variable is not currently not ever set.
do {
try {
mService.wait();
} catch (InterruptedException e) {
}
} while (!outResult.timeout && outResult.who == null);
}
break;
}
}
}
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
return res;
}
}
startActivity
//com/android/server/am/ActivityStarter.java
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup) {
if (TextUtils.isEmpty(reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
}
mLastStartReason = reason;
mLastStartActivityTimeMs = System.currentTimeMillis();
mLastStartActivityRecord[0] = null;
//手动注意
mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
inTask, allowPendingRemoteAnimationRegistryLookup);
if (outActivity != null) {
// mLastStartActivityRecord[0] is set in the call to startActivity above.
outActivity[0] = mLastStartActivityRecord[0];
}
return getExternalResult(mLastStartActivityResult);
}
startActivity
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
final Bundle verificationBundle
= options != null ? options.popAppVerificationBundle() : null;
........
//手动注意
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity);
}
startActivity
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
int result = START_CANCELED;
try {
mService.mWindowManager.deferSurfaceLayout();
//手动注意
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity);
} finally {
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
final ActivityStack stack = mStartActivity.getStack();
if (!ActivityManager.isStartResultSuccessful(result) && stack != null) {
stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
null /* intentResultData */, "startActivity", true /* oomAdj */);
}
mService.mWindowManager.continueSurfaceLayout();
}
postStartActivityProcessing(r, result, mTargetStack);
return result;
}
startActivityUnchecked
// com/android/server/am/ActivityStarter.java
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
computeLaunchingTaskFlags();
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
ActivityRecord reusedActivity = getReusableIntentActivity();
int preferredWindowingMode = WINDOWING_MODE_UNDEFINED;
int preferredLaunchDisplayId = DEFAULT_DISPLAY;
if (mOptions != null) {
preferredWindowingMode = mOptions.getLaunchWindowingMode();
preferredLaunchDisplayId = mOptions.getLaunchDisplayId();
}
// windowing mode and preferred launch display values from {@link LaunchParams} take
// priority over those specified in {@link ActivityOptions}.
if (!mLaunchParams.isEmpty()) {
if (mLaunchParams.hasPreferredDisplay()) {
preferredLaunchDisplayId = mLaunchParams.mPreferredDisplayId;
}
if (mLaunchParams.hasWindowingMode()) {
preferredWindowingMode = mLaunchParams.mWindowingMode;
}
}
if (reusedActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
// the device would otherwise leave the locked task.
if (mService.getLockTaskController().isLockTaskModeViolation(reusedActivity.getTask(),
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
// True if we are clearing top and resetting of a standard (default) launch mode
// ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
final boolean clearTopAndResetStandardLaunchMode =
(mLaunchFlags & (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED))
== (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
&& mLaunchMode == LAUNCH_MULTIPLE;
// If mStartActivity does not have a task associated with it, associate it with the
// reused activity's task. Do not do so if we're clearing top and resetting for a
// standard launchMode activity.
if (mStartActivity.getTask() == null && !clearTopAndResetStandardLaunchMode) {
mStartActivity.setTask(reusedActivity.getTask());
}
if (reusedActivity.getTask().intent == null) {
// This task was started because of movement of the activity based on affinity...
// Now that we are actually launching it, we can assign the base intent.
reusedActivity.getTask().setIntent(mStartActivity);
}
// This code path leads to delivering a new intent, we want to make sure we schedule it
// as the first operation, in case the activity will be resumed as a result of later
// operations.
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
final TaskRecord task = reusedActivity.getTask();
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);
// The above code can remove {@code reusedActivity} from the task, leading to the
// the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
// task reference is needed in the call below to
// {@link setTargetStackAndMoveToFrontIfNeeded}.
if (reusedActivity.getTask() == null) {
reusedActivity.setTask(task);
}
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
top.getTask().setIntent(mStartActivity);
}
deliverNewIntent(top);
}
}
mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
final ActivityRecord outResult =
outActivity != null && outActivity.length > 0 ? outActivity[0] : null;
// When there is a reused activity and the current result is a trampoline activity,
// set the reused activity as the result.
if (outResult != null && (outResult.finishing || outResult.noDisplay)) {
outActivity[0] = reusedActivity;
}
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do anything
// if that is the case, so this is it! And for paranoia, make sure we have
// correctly resumed the top activity.
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
if (reusedActivity != null) {
setTaskFromIntentActivity(reusedActivity);
if (!mAddingToTask && mReuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
if (outActivity != null && outActivity.length > 0) {
outActivity[0] = reusedActivity;
}
return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
}
}
}
if (mStartActivity.packageName == null) {
final ActivityStack sourceStack = mStartActivity.resultTo != null
? mStartActivity.resultTo.getStack() : null;
if (sourceStack != null) {
sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
null /* data */);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord topFocused = topStack.getTopActivity();
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
&& top.userId == mStartActivity.userId
&& top.app != null && top.app.thread != null
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
if (dontStart) {
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
ActivityOptions.abort(mOptions);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do
// anything if that is the case, so this is it!
return START_RETURN_INTENT_TO_CALLER;
}
deliverNewIntent(top);
// Don't use mStartActivity.task to show the toast. We're not starting a new activity
// but reusing 'top'. Fields in mStartActivity may not be fully initialized.
mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode,
preferredLaunchDisplayId, topStack);
return START_DELIVERED_TO_TOP;
}
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
// Should this be considered a new task?
int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
setTaskToCurrentTopOrCreateNewTask();
}
if (result != START_SUCCESS) {
return result;
}
mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
mStartActivity.getTask().taskId);
}
ActivityStack.logStartActivity(
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
//手动注意
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mService.mWindowManager.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
// will not update the focused stack. If starting the new activity now allows the
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityUnchecked");
}
//手动注意
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else if (mStartActivity != null) {
mSupervisor.mRecentTasks.add(mStartActivity.getTask());
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
preferredLaunchDisplayId, mTargetStack);
return START_SUCCESS;
}
startActivityLocked
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
TaskRecord rTask = r.getTask();
final int taskId = rTask.taskId;
// mLaunchTaskBehind tasks get placed at the back of the task stack. task中的上一个activity已被移除,或者ams重用该task,则将该task移到顶部
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
insertTaskAtTop(rTask, r);
}
TaskRecord task = null;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// All activities in task are finishing. 该task所有activity都finishing
continue;
}
if (task == rTask) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
if (!startIt) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+ task, new RuntimeException("here").fillInStackTrace());
r.createWindowContainer();
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
startIt = false;
}
}
}
// Place a new activity at top of stack, so it is next to interact with the user.
// If we are not placing the new activity frontmost, we do not want to deliver the
// onUserLeaving callback to the actual frontmost activity
final TaskRecord activityTask = r.getTask();
if (task == activityTask && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
mStackSupervisor.mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"startActivity() behind front, mUserLeaving=false");
}
task = activityTask;
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
// TODO: Need to investigate if it is okay for the controller to already be created by the
// time we get to this point. I think it is, but need to double check.
// Use test in b/34179495 to trace the call path.
if (r.getWindowContainerController() == null) {
r.createWindowContainer();
}
task.setFrontOfTask();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);
} else {
int transit = TRANSIT_ACTIVITY_OPEN;
if (newTask) {
if (r.mLaunchTaskBehind) {
transit = TRANSIT_TASK_OPEN_BEHIND;
} else {
// If a new task is being launched, then mark the existing top activity as
// supporting picture-in-picture while pausing only if the starting activity
// would not be considered an overlay on top of the current activity
// (eg. not fullscreen, or the assistant)
if (canEnterPipOnTaskSwitch(focusedTopActivity,
null /* toFrontTask */, r, options)) {
focusedTopActivity.supportsEnterPipOnTaskSwitch = true;
}
transit = TRANSIT_TASK_OPEN;
}
}
mWindowManager.prepareAppTransition(transit, keepCurTransition);
mStackSupervisor.mNoAnimActivities.remove(r);
}
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
// to reset it to make sure we apply affinities to move any
// existing activities from other tasks in to it.
// If the caller has requested that the target task be
// reset, then do so.
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
if (r.mLaunchTaskBehind) {
// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
// tell WindowManager that r is visible even though it is at the back of the stack.
r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
// created, if it still had one.
TaskRecord prevTask = r.getTask();
ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.getTask() != prevTask) {
prev = null;
}
// (2) The current activity is already displayed.
else if (prev.nowVisible) {
prev = null;
}
}
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
ActivityOptions.abort(options);
}
}
resumeFocusedStackTopActivityLocked
//com/android/server/am/ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!readyToResume()) {
return false;
}
if (targetStack != null && isFocusedStack(targetStack)) {
//手动注意
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || !r.isState(RESUMED)) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
} else if (r.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}
resumeTopActivityUncheckedLocked
//com/android/server/am/ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
//手动注意
result = resumeTopActivityInnerLocked(prev, options);
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
// end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
// to ensure any necessary pause logic occurs. In the case where the Activity will be
// shown regardless of the lock screen, the call to
// {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
resumeTopActivityInnerLocked
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
//系统没有进入booting或booted状态,则不允许启动Activity
if (!mService.mBooting && !mService.mBooted) {
// Not ready yet!
return false;
}
// Find the next top-most activity to resume in this stack that is not finishing and is
// focusable. If it is not focusable, we will fall into the case below to resume the
// top activity in the next focusable task.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
final boolean hasRunningActivity = next != null;
// TODO: Maybe this entire condition can get removed?
if (hasRunningActivity && !isAttached()) {
return false;
}
//top running之后的任意处于初始化状态且有显示StartingWindow, 则移除StartingWindow
mStackSupervisor.cancelInitializingActivities();
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
if (!hasRunningActivity) {
// There are no activities left in the stack, let's look somewhere else.
return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
}
next.delayedResume = false;
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.isState(RESUMED)
&& mStackSupervisor.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Top activity resumed " + next);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
if (shouldSleepOrShutDownActivities()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Going to sleep and all paused");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
// Make sure that the user who owns this activity is started. If not,
// we will just leave it as is because someone should be bringing
// another user's activities to the top of the stack.
if (!mService.mUserController.hasStartedUserState(next.userId)) {
Slog.w(TAG, "Skipping resume of top activity " + next
+ ": user " + next.userId + " is stopped");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(next);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
// If we are currently pausing an activity, then don't do anything until that is done.
if (!mStackSupervisor.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
boolean lastResumedCanPip = false;
ActivityRecord lastResumed = null;
final ActivityStack lastFocusedStack = mStackSupervisor.getLastStack();
if (lastFocusedStack != null && lastFocusedStack != this) {
// So, why aren't we using prev here??? See the param comment on the method. prev doesn't
// represent the last resumed activity. However, the last focus stack does if it isn't null.
lastResumed = lastFocusedStack.mResumedActivity;
if (userLeaving && inMultiWindowMode() && lastFocusedStack.shouldBeVisible(next)) {
// The user isn't leaving if this stack is the multi-window mode and the last
// focused stack should still be visible.
if(DEBUG_USER_LEAVING) Slog.i(TAG_USER_LEAVING, "Overriding userLeaving to false"
+ " next=" + next + " lastResumed=" + lastResumed);
userLeaving = false;
}
lastResumedCanPip = lastResumed != null && lastResumed.checkEnterPictureInPictureState(
"resumeTopActivity", userLeaving /* beforeStopping */);
}
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity
// to be paused, while at the same time resuming the new resume activity only if the
// previous activity can't go into Pip since we want to give Pip activities a chance to
// enter Pip before resuming the next activity.
final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0
&& !lastResumedCanPip;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
pausing |= startPausingLocked(userLeaving, false, next, false);
}
if (pausing && !resumeWhilePausing) {
if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
"resumeTopActivityLocked: Skip resume: need to start pausing");
// At this point we want to put the upcoming activity's process
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
if (next.app != null && next.app.thread != null) {
mService.updateLruProcessLocked(next.app, true, null);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (lastResumed != null) {
lastResumed.setWillCloseOrEnterPip(true);
}
return true;
} else if (mResumedActivity == next && next.isState(RESUMED)
&& mStackSupervisor.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"no-history finish of " + mLastNoHistoryActivity + " on new resume");
requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
null, "resume-no-history", false);
mLastNoHistoryActivity = null;
}
if (prev != null && prev != next) {
if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
&& next != null && !next.nowVisible) {
mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Resuming top, waiting visible to hide: " + prev);
} else {
// The next activity is already visible, so hide the previous
// activity's windows right now so we can show the new one ASAP.
// We only do this if the previous is finishing, which should mean
// it is on top of the one being resumed so hiding it quickly
// is good. Otherwise, we want to do the normal route of allowing
// the resumed activity to be shown so we can decide if the
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) {
prev.setVisibility(false);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Not waiting for visible to hide: " + prev + ", waitingVisible="
+ mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
+ ", nowVisible=" + next.nowVisible);
} else {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Previous already visible but still waiting to hide: " + prev
+ ", waitingVisible="
+ mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
+ ", nowVisible=" + next.nowVisible);
}
}
}
// Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false, next.userId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ next.packageName + ": " + e);
}
// We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare close transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(prev)) {
anim = false;
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
} else {
mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
? TRANSIT_ACTIVITY_CLOSE
: TRANSIT_TASK_CLOSE, false);
}
prev.setVisibility(false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
} else {
mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind
? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN, false);
}
}
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
} else {
mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
}
}
if (anim) {
next.applyOptionsLocked();
} else {
next.clearOptionsLocked();
}
mStackSupervisor.mNoAnimActivities.clear();
ActivityStack lastStack = mStackSupervisor.getLastStack();
//进程已存在的情况
if (next.app != null && next.app.thread != null) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
+ " stopped=" + next.stopped + " visible=" + next.visible);
// If the previous activity is translucent, force a visibility update of
// the next activity, so that it's added to WM's opening app list, and
// transition animation can be set up properly.
// For example, pressing Home button with a translucent activity in focus.
// Launcher is already visible in this case. If we don't add it to opening
// apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
// TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
final boolean lastActivityTranslucent = lastStack != null
&& (lastStack.inMultiWindowMode()
|| (lastStack.mLastPausedActivity != null
&& !lastStack.mLastPausedActivity.fullscreen));
// The contained logic must be synchronized, since we are both changing the visibility
// and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will
// ultimately cause the client code to schedule a layout. Since layouts retrieve the
// current {@link Configuration}, we must ensure that the below code updates it before
// the layout can occur.
synchronized(mWindowManager.getWindowManagerLock()) {
// This activity is now becoming visible.
if (!next.visible || next.stopped || lastActivityTranslucent) {
next.setVisibility(true);
}
// schedule launch ticks to collect information about slow apps.
next.startLaunchTickingLocked();
ActivityRecord lastResumedActivity =
lastStack == null ? null :lastStack.mResumedActivity;
final ActivityState lastState = next.getState();
mService.updateCpuStats();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
+ " (in existing)");
next.setState(RESUMED, "resumeTopActivityInnerLocked");
mService.updateLruProcessLocked(next.app, true, null);
updateLRUListLocked(next);
mService.updateOomAdjLocked();
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
boolean notUpdated = true;
if (mStackSupervisor.isFocusedStack(this)) {
// We have special rotation behavior when here is some active activity that
// requests specific orientation or Keyguard is locked. Make sure all activity
// visibilities are set correctly as well as the transition is updated if needed
// to get the correct rotation behavior. Otherwise the following call to update
// the orientation may cause incorrect configurations delivered to client as a
// result of invisible window resize.
// TODO: Remove this once visibilities are set correctly immediately when
// starting an activity.
notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
true /* markFrozenIfConfigChanged */, false /* deferResume */);
}
if (notUpdated) {
// The configuration update wasn't able to keep the existing
// instance of the activity, and instead started a new one.
// We should be all done, but let's just make sure our activity
// is still at the top and schedule another run if something
// weird happened.
ActivityRecord nextNext = topRunningActivityLocked();
if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
"Activity config changed during resume: " + next
+ ", new next: " + nextNext);
if (nextNext != next) {
// Do over!
mStackSupervisor.scheduleResumeTopActivities();
}
if (!next.visible || next.stopped) {
next.setVisibility(true);
}
next.completeResumeLocked();
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
try {
final ClientTransaction transaction = ClientTransaction.obtain(next.app.thread,
next.appToken);
// Deliver all pending results.
ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Delivering results to " + next + ": " + a);
transaction.addCallback(ActivityResultItem.obtain(a));
}
}
if (next.newIntents != null) {
transaction.addCallback(NewIntentItem.obtain(next.newIntents,
false /* andPause */));
}
// Well the app will no longer be stopped.
// Clear app token stopped state in window manager if needed.
next.notifyAppResumed(next.stopped);
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
System.identityHashCode(next), next.getTask().taskId,
next.shortComponentName);
next.sleeping = false;
mService.getAppWarningsLocked().onResumeActivity(next);
mService.showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.repProcState,
mService.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
+ next);
} catch (Exception e) {
// Whoops, need to restart this activity!
if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
+ lastState + ": " + next);
next.setState(lastState, "resumeTopActivityInnerLocked");
// lastResumedActivity being non-null implies there is a lastStack present.
if (lastResumedActivity != null) {
lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
}
Slog.i(TAG, "Restarting because process died: " + next);
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else if (SHOW_APP_STARTING_PREVIEW && lastStack != null
&& lastStack.isTopStackOnDisplay()) {
next.showStartingWindow(null /* prev */, false /* newTask */,
false /* taskSwitch */);
}
mStackSupervisor.startSpecificActivityLocked(next, true, false);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
}
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
next.completeResumeLocked();
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
"resume-exception", true);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(null /* prev */, false /* newTask */,
false /* taskSwich */);
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
//手动注意
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
startSpecificActivityLocked
//com/android/server/am/ActivityStackSupervisor.java
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);
}
//真正的启动Activity
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);
}
startProcessLocked->startProcessLocked->startProcessLocked->startProcess
//com/android/server/am/ActivityManagerService.java
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);
}
}
Process.start()
//android/os/Process.java
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);
}
start
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
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);
}
}
zygoteSendArgsAndGetResult
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();
//通过socket发送
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);
}
}
此时Zygote进程收到创建子进程的消息 runSelectLoop
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
//手动注意
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This shows up as
// a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
if (!mIsForkChild) {
// We're in the server so any exception here is one that has taken place
// pre-fork while processing commands or reading / writing from the
// control socket. Make a loud noise about any such exceptions so that
// we know exactly what failed and why.
Slog.e(TAG, "Exception executing zygote command: ", e);
// Make sure the socket is closed so that the other end knows immediately
// that something has gone wrong and doesn't time out waiting for a
// response.
ZygoteConnection conn = peers.remove(i);
conn.closeSocket();
fds.remove(i);
} else {
// We're in the child so any exception caught here has happened post
// fork and before we execute ActivityThread.main (or any other main()
// method). Log the details of the exception and bring down the process.
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
} finally {
// Reset the child flag, in the event that the child process is a child-
// zygote. The flag will not be consulted this loop pass after the Runnable
// is returned.
mIsForkChild = false;
}
}
}
}
}
processOneCommand
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//获取应用程序进程的启动参数
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
// readArgumentList returns null only when it has reached EOF with no available
// data to read. This will only happen when the remote socket has disconnected.
if (args == null) {
isEof = true;
return null;
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
parsedArgs = new Arguments(args);
if (parsedArgs.abiListQuery) {
handleAbiListQuery();
return null;
}
if (parsedArgs.preloadDefault) {
handlePreload();
return null;
}
if (parsedArgs.preloadPackage != null) {
handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
return null;
}
if (parsedArgs.apiBlacklistExemptions != null) {
handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
return null;
}
if (parsedArgs.hiddenApiAccessLogSampleRate != -1) {
handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate);
return null;
}
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: " +
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
}
applyUidSecurityPolicy(parsedArgs, peer);
applyInvokeWithSecurityPolicy(parsedArgs, peer);
applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null;
if (parsedArgs.rlimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d);
}
int[] fdsToIgnore = null;
if (parsedArgs.invokeWith != null) {
try {
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
Os.fcntlInt(childPipeFd, F_SETFD, 0);
fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
} catch (ErrnoException errnoEx) {
throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
}
}
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
* in the child process before it switches from Zygote-root to
* the UID and privileges of the application being launched.
*
* In order to avoid "bad file descriptor" errors when the
* two LocalSocket objects are closed, the Posix file
* descriptors are released via a dup2() call which closes
* the socket and substitutes an open descriptor to /dev/null.
*/
int [] fdsToClose = { -1, -1 };
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
fdsToClose[0] = fd.getInt$();
}
fd = zygoteServer.getServerSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
}
fd = null;
//手动注意 创建应用程序进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
//当前代码逻辑运行在子进程中 如果pid等于0,则说明当前代码逻辑运行在新创建的子进程(应用程序进程)中,这时就会调用handleChildProc方法来处理应用程序进程,
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//手动注意 处理应用程序进程
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
handleChildProc
//com/android/internal/os/ZygoteConnection.java
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
* objects still need to be closed properly.
*/
closeSocket();
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if (!isZygote) {
//手动注意
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
}
zygoteInit
//com/android/internal/os/ZygoteInit.java
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
//此方法设置一个默认的crashHandler
RuntimeInit.commonInit();
//新创建的应用程序进程中创建Binder线程池.
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
//com/android/internal/os/RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);//反射回调ActivityThread的main方法
}
main
//android/app/ActivityThread.java
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("" );
//创建主线程Looper
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) {
//创建主线程Handler
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开始工作
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
attach()
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("" ,
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//将回调绑定在ams中
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} 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();
mInstrumentation.basicInit(this);
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
//回调application中的onCreate方法。
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);
}
attachApplication
//com/android/server/am/ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
//com/android/server/am/ActivityManagerService.java
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// 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.
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
// It's possible that process called attachApplication before we got a chance to
// update the internal state.
if (app == null && startSeq > 0) {
final ProcessRecord pending = mPendingStarts.get(startSeq);
if (pending != null && pending.startUid == callingUid
&& handleProcessStartedLocked(pending, pid, pending.usingWrapper,
startSeq, true)) {
app = pending;
}
}
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);
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;
}
}
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);
ProfilerInfo profilerInfo = null;
String preBindAgent = null;
if (mProfileApp != null && mProfileApp.equals(processName)) {
mProfileProc = app;
if (mProfilerInfo != null) {
// Send a profiler info object to the app if either a file is given, or
// an agent should be loaded at bind-time.
boolean needsInfo = mProfilerInfo.profileFile != null
|| mProfilerInfo.attachAgentDuringBind;
profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null;
if (mProfilerInfo.agent != null) {
preBindAgent = mProfilerInfo.agent;
}
}
} else if (app.instr != null && app.instr.mProfileFile != null) {
profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
null, false);
}
if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
// We need to do a debuggable check here. See setAgentApp for why the check is
// postponed to here.
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
String agent = mAppAgentMap.get(processName);
// Do not overwrite already requested agent.
if (profilerInfo == null) {
profilerInfo = new ProfilerInfo(null, null, 0, false, false,
mAppAgentMap.get(processName), true);
} else if (profilerInfo.agent == null) {
profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true);
}
}
}
if (profilerInfo != null && profilerInfo.profileFd != null) {
profilerInfo.profileFd = profilerInfo.profileFd.dup();
if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) {
clearProfilerLocked();
}
}
// We deprecated Build.SERIAL and it is not accessible to
// apps that target the v2 security sandbox and to apps that
// target APIs higher than O MR1. Since access to the serial
// is now behind a permission we push down the value.
final String buildSerial = (appInfo.targetSandboxVersion < 2
&& appInfo.targetSdkVersion < Build.VERSION_CODES.P)
? sTheRealBuildSerial : Build.UNKNOWN;
// 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;
}
}
}
}
}
}
// If we were asked to attach an agent on startup, do so now, before we're binding
// application code.
if (preBindAgent != null) {
thread.attachAgent(preBindAgent);
}
// Figure out whether the app needs to run in autofill compat mode.
boolean isAutofillCompatEnabled = false;
if (UserHandle.getAppId(app.info.uid) >= Process.FIRST_APPLICATION_UID) {
final AutofillManagerInternal afm = LocalServices.getService(
AutofillManagerInternal.class);
if (afm != null) {
isAutofillCompatEnabled = afm.isCompatibilityModeRequested(
app.info.packageName, app.info.versionCode, app.userId);
}
}
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(app);
if (app.isolatedEntryPoint != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
} else 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, isAutofillCompatEnabled);
} 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, isAutofillCompatEnabled);
}
if (profilerInfo != null) {
profilerInfo.closeFd();
profilerInfo = null;
}
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...
if (normalMode) {
try {
//开启activity
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;
}
bindApplication
//android/app/ActivityThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, boolean autofillCompatibilityEnabled) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
for (Object oname : services.keySet()) {
if (services.get(oname) == null) {
continue; // AM just passed in a null service.
}
String name = (String) oname;
// See b/79378449 about the following exemption.
switch (name) {
case "package":
case Context.WINDOW_SERVICE:
continue;
}
if (ServiceManager.getService(name) == null) {
Log.wtf(TAG, "Service " + name + " should be accessible by this app");
}
}
}
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
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.enableBinderTracking = enableBinderTracking;
data.trackAllocation = trackAllocation;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
data.buildSerial = buildSerial;
data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
sendMessage(H.BIND_APPLICATION, data);
}
handleBindApplication
private void handleBindApplication(AppBindData data) {
// Register the UI Thread as a sensitive thread to the runtime.
VMRuntime.registerSensitiveThread();
if (data.trackAllocation) {
DdmVmInternal.enableRecentAllocations(true);
}
// Note when this process has started.
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
mProfiler = new Profiler();
String agent = null;
if (data.initProfilerInfo != null) {
mProfiler.profileFile = data.initProfilerInfo.profileFile;
mProfiler.profileFd = data.initProfilerInfo.profileFd;
mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval;
mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler;
mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput;
if (data.initProfilerInfo.attachAgentDuringBind) {
agent = data.initProfilerInfo.agent;
}
}
// send up app name; do this *before* waiting for debugger
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
VMRuntime.setProcessPackageName(data.appInfo.packageName);
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
}
// If the app is Honeycomb MR1 or earlier, switch its AsyncTask
// implementation to use the pool executor. Normally, we use the
// serialized executor as the default. This has to happen in the
// main thread so the main looper is set right.
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
Message.updateCheckRecycle(data.appInfo.targetSdkVersion);
// Prior to P, internal calls to decode Bitmaps used BitmapFactory,
// which may scale up to account for density. In P, we switched to
// ImageDecoder, which skips the upscale to save memory. ImageDecoder
// needs to still scale up in older apps, in case they rely on the
// size of the Bitmap without considering its density.
ImageDecoder.sApiLevel = data.appInfo.targetSdkVersion;
/*
* Before spawning a new process, reset the time zone to be the system time zone.
* This needs to be done because the system time zone could have changed after the
* the spawning of this process. Without doing this this process would have the incorrect
* system time zone.
*/
TimeZone.setDefault(null);
/*
* Set the LocaleList. This may change once we create the App Context.
*/
LocaleList.setDefault(data.config.getLocales());
synchronized (mResourcesManager) {
/*
* Update the system configuration since its preloaded and might not
* reflect configuration changes. The configuration object passed
* in AppBindData can be safely assumed to be up to date
*/
mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
mCurDefaultDisplayDpi = data.config.densityDpi;
// This calls mResourcesManager so keep it within the synchronized block.
applyCompatConfiguration(mCurDefaultDisplayDpi);
}
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
if (agent != null) {
handleAttachAgent(agent, data.info);
}
/**
* Switch this process to density compatibility mode if needed.
*/
if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
== 0) {
mDensityCompatMode = true;
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
}
updateDefaultDensity();
final String use24HourSetting = mCoreSettings.getString(Settings.System.TIME_12_24);
Boolean is24Hr = null;
if (use24HourSetting != null) {
is24Hr = "24".equals(use24HourSetting) ? Boolean.TRUE : Boolean.FALSE;
}
// null : use locale default for 12/24 hour formatting,
// false : use 12 hour format,
// true : use 24 hour format.
DateFormat.set24HourTimePref(is24Hr);
View.mDebugViewAttributes =
mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
StrictMode.initThreadDefaults(data.appInfo);
StrictMode.initVmDefaults(data.appInfo);
// We deprecated Build.SERIAL and only apps that target pre NMR1
// SDK can see it. Since access to the serial is now behind a
// permission we push down the value and here we fix it up
// before any app code has been loaded.
try {
Field field = Build.class.getDeclaredField("SERIAL");
field.setAccessible(true);
field.set(Build.class, data.buildSerial);
} catch (NoSuchFieldException | IllegalAccessException e) {
/* ignore */
}
if (data.debugMode != ApplicationThreadConstants.DEBUG_OFF) {
// XXX should have option to change the port.
Debug.changeDebugPort(8100);
if (data.debugMode == ApplicationThreadConstants.DEBUG_WAIT) {
Slog.w(TAG, "Application " + data.info.getPackageName()
+ " is waiting for the debugger on port 8100...");
IActivityManager mgr = ActivityManager.getService();
try {
mgr.showWaitingForDebugger(mAppThread, true);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
Debug.waitForDebugger();
try {
mgr.showWaitingForDebugger(mAppThread, false);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} else {
Slog.w(TAG, "Application " + data.info.getPackageName()
+ " can be debugged on port 8100...");
}
}
// Allow application-generated systrace messages if we're debuggable.
boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
Trace.setAppTracingAllowed(isAppDebuggable);
ThreadedRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE);
if (isAppDebuggable && data.enableBinderTracking) {
Binder.enableTracing();
}
/**
* Initialize the default http proxy in this process for the reasons we set the time zone.
*/
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies");
final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
// In pre-boot mode (doing initial launch to collect password), not
// all system is up. This includes the connectivity service, so don't
// crash if we can't get it.
final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
Proxy.setHttpProxySystemProperty(proxyInfo);
} catch (RemoteException e) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw e.rethrowFromSystemServer();
}
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Instrumentation info affects the class loader, so load it before
// setting up the app context.
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
try {
ii = new ApplicationPackageManager(null, getPackageManager())
.getInstrumentationInfo(data.instrumentationName, 0);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find instrumentation info for: " + data.instrumentationName);
}
// Warn of potential ABI mismatches.
if (!Objects.equals(data.appInfo.primaryCpuAbi, ii.primaryCpuAbi)
|| !Objects.equals(data.appInfo.secondaryCpuAbi, ii.secondaryCpuAbi)) {
Slog.w(TAG, "Package uses different ABI(s) than its instrumentation: "
+ "package[" + data.appInfo.packageName + "]: "
+ data.appInfo.primaryCpuAbi + ", " + data.appInfo.secondaryCpuAbi
+ " instrumentation[" + ii.packageName + "]: "
+ ii.primaryCpuAbi + ", " + ii.secondaryCpuAbi);
}
mInstrumentationPackageName = ii.packageName;
mInstrumentationAppDir = ii.sourceDir;
mInstrumentationSplitAppDirs = ii.splitSourceDirs;
mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
mInstrumentedAppDir = data.info.getAppDir();
mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
mInstrumentedLibDir = data.info.getLibDir();
} else {
ii = null;
}
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
updateLocaleListFromAppContext(appContext,
mResourcesManager.getConfiguration().getLocales());
if (!Process.isIsolated()) {
final int oldMask = StrictMode.allowThreadDiskWritesMask();
try {
setupGraphicsSupport(appContext);
} finally {
StrictMode.setThreadPolicyMask(oldMask);
}
} else {
ThreadedRenderer.setIsolatedProcess(true);
}
// If we use profiles, setup the dex reporter to notify package manager
// of any relevant dex loads. The idle maintenance job will use the information
// reported to optimize the loaded dex files.
// Note that we only need one global reporter per app.
// Make sure we do this before calling onCreate so that we can capture the
// complete application startup.
if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
}
// Install the Network Security Config Provider. This must happen before the application
// code is loaded to prevent issues with instances of TLS objects being created before
// the provider is installed.
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "NetworkSecurityConfigProvider.install");
NetworkSecurityConfigProvider.install(appContext);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Continue loading instrumentation.
if (ii != null) {
ApplicationInfo instrApp;
try {
instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
UserHandle.myUserId());
} catch (RemoteException e) {
instrApp = null;
}
if (instrApp == null) {
instrApp = new ApplicationInfo();
}
ii.copyTo(instrApp);
instrApp.initForUser(UserHandle.myUserId());
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true, false);
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
+ data.instrumentationName + ": " + e.toString(), e);
}
final ComponentName component = new ComponentName(ii.packageName, ii.name);
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
if (mProfiler.profileFile != null && !ii.handleProfiling
&& mProfiler.profileFd == null) {
mProfiler.handlingProfiling = true;
final File file = new File(mProfiler.profileFile);
file.getParentFile().mkdirs();
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
} else {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
}
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
} else {
// Small heap, clamp to the current growth limit and let the heap release
// pages after the growth limit to the non growth limit capacity. b/18387825
dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
}
// Allow disk access during application and provider setup. This could
// block processing ordered broadcasts, but later processing would
// probably end up doing the same disk access.
Application app;
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
app = data.info.makeApplication(data.restrictedBackupMode, null);
// Propagate autofill compat state
app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
} finally {
// If the app targets < O-MR1, or doesn't change the thread policy
// during startup, clobber the policy to maintain behavior of b/36951662
if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
|| StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
StrictMode.setThreadPolicy(savedPolicy);
}
}
// Preload fonts resources
FontsContract.setApplicationContextForResources(appContext);
if (!Process.isIsolated()) {
try {
final ApplicationInfo info =
getPackageManager().getApplicationInfo(
data.appInfo.packageName,
PackageManager.GET_META_DATA /*flags*/,
UserHandle.myUserId());
if (info.metaData != null) {
final int preloadedFontsResource = info.metaData.getInt(
ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
if (preloadedFontsResource != 0) {
data.info.getResources().preloadFonts(preloadedFontsResource);
}
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
attachApplicationLocked
//com/android/server/am/ActivityStackSupervisor.java
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
if (!isFocusedStack(stack)) {
continue;
}
stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
final ActivityRecord top = stack.topRunningActivityLocked();
final int size = mTmpActivityList.size();
for (int i = 0; i < size; i++) {
final ActivityRecord activity = mTmpActivityList.get(i);
if (activity.app == null && app.uid == activity.info.applicationInfo.uid
&& processName.equals(activity.processName)) {
try {
if (realStartActivityLocked(activity, app,
top == activity /* andResume */, true /* checkConfig */)) {
didSomething = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting activity "
+ top.intent.getComponent().flattenToShortString(), e);
throw e;
}
}
}
}
}
if (!didSomething) {
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
return didSomething;
}
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;
}
final TaskRecord task = r.getTask();
final ActivityStack stack = task.getStack();
beginDeferResume();
try {
r.startFreezingScreenLocked(app, 0);
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
r.setProcess(app);
if (getKeyguardController().isKeyguardLocked()) {
r.notifyUnknownVisibilityLaunched();
}
// 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) {
// 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.
ensureVisibilityAndConfig(r, r.getDisplayId(),
false /* markFrozenIfConfigChanged */, true /* deferResume */);
}
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);
}
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);
}
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 LockTaskController lockTaskController = mService.getLockTaskController();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
|| task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV
|| (task.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED
&& lockTaskController.getLockTaskModeState()
== LOCK_TASK_MODE_LOCKED)) {
lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */);
}
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.isActivityTypeHome()) {
// 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.getAppWarningsLocked().onStartActivity(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;
ProfilerInfo profilerInfoSvc = mService.mProfilerInfo;
if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) {
if (profilerInfoSvc.profileFd != null) {
try {
profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup();
} catch (IOException e) {
profilerInfoSvc.closeFd();
}
}
profilerInfo = new ProfilerInfo(profilerInfoSvc);
}
}
}
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);
logIfTransactionTooLarge(r.intent, r.icicle);
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
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, mService.isNextTransitionForward(),
profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
&& mService.mHasHeavyWeightFeature) {
// 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;
}
} finally {
endDeferResume();
}
r.launchFailed = false;
if (stack.updateLRUListLocked(r)) {
Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
}
// TODO(lifecycler): Resume or pause requests are done as part of launch transaction,
// so updating the state should be done accordingly.
if (andResume && readyToResume()) {
// 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.setState(PAUSED, "realStartActivityLocked");
}
// 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.getActivityStartController().startSetupActivity();
}
// 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;
}
execute
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}