android activity 管理器AMS----概述
AMS & WMS,应该是app端打交道最多的2个framwork层的service。
ActivityManagerService 是android提供给用于管理Activity运行状态的系统进程。
本系列共分3个部分,概述,ActivityStatck & Activiy Task.
AMS 主要用于管理Activity之间的交互问题。
核心问题有以下几个:
1.activity 生命周期管理
2.intent是怎么传递数据的。(可能跨进程,以及双向传递)
3.launchmode是怎么使用的。(Task的概念)
一. AMS概述
首先AMS 是一个同我们开发的service非常相似的一个service,只不过它的作用是管理activity。
所以AMS是一个进程,并且当开机以后,它就常驻在系统里面,归ServiceManager调度。
而AMS启动后,它开始有一个线程监听处理客户的需求。
一下为android5.0 的代码:
\frameworks\base\services\java\com\android\server\SystemServera.java
- private void startBootstrapServices() {
- // 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.
- mInstaller = mSystemServiceManager.startService(Installer.class);
- // Activity manager runs the show.
- mActivityManagerService = mSystemServiceManager.startService(
- ActivityManagerService.Lifecycle.class).getService();
- mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
- // 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).
- mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
- // Now that the power manager has been started, let the activity manager
- // initialize power management features.
- mActivityManagerService.initPowerManagement();
- // Display manager is needed to provide display metrics before package manager
- // starts up.
- mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
- // We need the default display before we can initialize the package manager.
- mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
- // 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.
- Slog.i(TAG, "Package Manager");
- mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
- mFirstBoot = mPackageManagerService.isFirstBoot();
- mPackageManager = mSystemContext.getPackageManager();
- Slog.i(TAG, "User Service");
- ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
- // Initialize attribute cache used to cache resources from packages.
- AttributeCache.init(mSystemContext);
- // Set up the Application instance for the system process and get started.
- mActivityManagerService.setSystemProcess();
- }
startBootstrapServices
可以看到AMS在这里启动。而这个函数startBootstrapServices是在run方法中运行。
- public ActivityManagerService(Context systemContext) {
- mContext = systemContext;
- mFactoryTest = FactoryTest.getMode();
- mSystemThread = ActivityThread.currentActivityThread();
- Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
- mHandlerThread = new ServiceThread(TAG,
- android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
- mHandlerThread.start();
- mHandler = new MainHandler(mHandlerThread.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);
- // TODO: Move creation of battery stats service outside of activity manager service.
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- systemDir.mkdirs();
- mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
- mBatteryStatsService.getActiveStatistics().readLocked();
- mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
- mOnBattery = DEBUG_POWER ? true
- : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
- mBatteryStatsService.getActiveStatistics().setCallback(this);
- mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
- mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);
- mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
- // User 0 is the first and only user that runs at boot.
- mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
- mUserLru.add(Integer.valueOf(0));
- updateStartedUserArrayLocked();
- GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
- ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
- mConfiguration.setToDefaults();
- mConfiguration.setLocale(Locale.getDefault());
- mConfigurationSeq = mConfiguration.seq = 1;
- mProcessCpuTracker.init();
- mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
- mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
- mStackSupervisor = new ActivityStackSupervisor(this);
- mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);
- mProcessCpuThread = new Thread("CpuTracker") {
- @Override
- public void run() {
- 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);
- }
- }
- }
- };
- mLockToAppRequest = new LockToAppRequestDialog(mContext, this);
- Watchdog.getInstance().addMonitor(this);
- Watchdog.getInstance().addThread(mHandler);
- }
ActivityManagerService
- mStackSupervisor = new ActivityStackSupervisor(this);
- mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);
这两句是ActivityStack & ActivityTask设置的地方。
public void setSystemProcess()就比较简单了,它不仅注册了自己一个server, 还注册了其他的server。
- ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
- ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
- ServiceManager.addService("meminfo", new MemBinder(this));
- ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
- ServiceManager.addService("dbinfo", new DbBinder(this));
- if (MONITOR_CPU_USAGE) {
- ServiceManager.addService("cpuinfo", new CpuBinder(this));
- }
- ServiceManager.addService("permission", new PermissionController(this));
二.Activit状态管理---ActivityStack
1.ActivityState
定义了如下状态:
状态变化图。
三:startActivity
startActivity@ActivityManagerService.java
startActivityAsUser@ActivityManagerService.java
startActivityMayWait@ActivityStack.java
startActivityLocked@ActivityStack.java
sartActivityUncheckedLocked@ActivityStack.java
这5个函数先后关系,就是上面的顺序。
- public final int startActivity(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle options) {
- return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
- resultWho, requestCode, startFlags, profilerInfo, options,
- UserHandle.getCallingUserId());
- }
多了一个
- UserHandle.getCallingUserId()
调用者的Userid值,通过bind机制获得的。
- @Override
- public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
- enforceNotIsolatedCaller("startActivity");
- userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
- false, ALLOW_FULL_ONLY, "startActivity", null);
- // TODO: Switch to user app stacks here.
- return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- profilerInfo, null, null, options, false, userId, null, null);
- }
enforceNotIsolatedCaller 的目的是确认当前用户是否属于被隔离的对象。
接下来是 startActivityMayWait
startActivityMayWait
- ActivityStackSupervisor.startActivityMayWait
- final 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 config,
- Bundle options, boolean ignoreTargetSecurity, int userId,
- IActivityContainer iContainer, TaskRecord inTask) {
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- boolean componentSpecified = intent.getComponent() != null;
- // Don't modify the client's object!
- intent = new Intent(intent);
- // Collect information about the target of the Intent.
- ActivityInfo aInfo =
- resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
- ActivityContainer container = (ActivityContainer)iContainer;
- synchronized (mService) {
- if (container != null && container.mParentActivity != null &&
- container.mParentActivity.state != RESUMED) {
- // Cannot start a child activity if the parent is not resumed.
- return ActivityManager.START_CANCELED;
- }
- 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;
- }
- final ActivityStack stack;
- if (container == null || container.mStack.isOnHomeDisplay()) {
- stack = mFocusedStack;
- } else {
- stack = container.mStack;
- }
- stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 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) {
- // 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)) {
- if (mService.mHeavyWeightProcess != null &&
- (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
- !mService.mHeavyWeightProcess.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());
- ActivityOptions.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 (mService.mHeavyWeightProcess.activities.size() > 0) {
- ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
- hist.packageName);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
- hist.task.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;
- try {
- ResolveInfo rInfo =
- AppGlobals.getPackageManager().resolveIntent(
- intent, null,
- PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, userId);
- aInfo = rInfo != null ? rInfo.activityInfo : null;
- aInfo = mService.getActivityInfoForUser(aInfo, userId);
- } catch (RemoteException e) {
- aInfo = null;
- }
- }
- }
- }
- int res = startActivityLocked(caller, intent, resolvedType, aInfo,
- voiceSession, voiceInteractor, resultTo, resultWho,
- requestCode, callingPid, callingUid, callingPackage,
- realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
- componentSpecified, null, container, inTask);
- 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(config, null, false, false);
- }
- if (outResult != null) {
- outResult.result = res;
- if (res == ActivityManager.START_SUCCESS) {
- mWaitingActivityLaunched.add(outResult);
- do {
- try {
- mService.wait();
- } catch (InterruptedException e) {
- }
- } while (!outResult.timeout && outResult.who == null);
- } else if (res == ActivityManager.START_TASK_TO_FRONT) {
- ActivityRecord r = stack.topRunningActivityLocked(null);
- if (r.nowVisible && r.state == RESUMED) {
- outResult.timeout = false;
- outResult.who = new ComponentName(r.info.packageName, r.info.name);
- outResult.totalTime = 0;
- outResult.thisTime = 0;
- } else {
- outResult.thisTime = SystemClock.uptimeMillis();
- mWaitingActivityVisible.add(outResult);
- do {
- try {
- mService.wait();
- } catch (InterruptedException e) {
- }
- } while (!outResult.timeout && outResult.who == null);
- }
- }
- }
- return res;
- }
- }
首先判断是不是显示intent,
调用resolveActivity来进行查找。这里有一段注释:
- // Store the found target back into the intent, because now that
- // we have it we never want to do this again. For example, if the
- // user navigates back to this point in the history, we should
- // always restart the exact same activity.
为了确保在history里面的intent统一,只查找一次,获取ActivityInfo。
判断当前目标进程是不是重量级进程。
最后调用startActivityLocked来进一部启动。
如果onResult不为空,还需要将函数的结果写入这个变量中。在onResult的处理上,有可能会wait,所以这个函数叫startActivityMayWait。
StartActivityLocked
顾名思义,它是线程安全的。
- final int startActivityLocked(IApplicationThread caller,
- Intent intent, String resolvedType, ActivityInfo aInfo,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- IBinder resultTo, String resultWho, int requestCode,
- int callingPid, int callingUid, String callingPackage,
- int realCallingPid, int realCallingUid, int startFlags, Bundle options,
- boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
- ActivityContainer container, TaskRecord inTask) {
- int err = ActivityManager.START_SUCCESS;
- ProcessRecord callerApp = null;
- if (caller != null) {
- callerApp = mService.getRecordForAppLocked(caller);
- if (callerApp != null) {
- callingPid = callerApp.pid;
- callingUid = callerApp.info.uid;
- } else {
- Slog.w(TAG, "Unable to find app for caller " + caller
- + " (pid=" + callingPid + ") when starting: "
- + intent.toString());
- err = ActivityManager.START_PERMISSION_DENIED;
- }
- }
- final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
- if (err == ActivityManager.START_SUCCESS) {
- Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
- + "} from uid " + callingUid
- + " on display " + (container == null ? (mFocusedStack == null ?
- Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
- (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
- container.mActivityDisplay.mDisplayId)));
- }
- ActivityRecord sourceRecord = null;
- ActivityRecord resultRecord = null;
- if (resultTo != null) {
- sourceRecord = isInAnyStackLocked(resultTo);
- if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
- "Will send result to " + resultTo + " " + sourceRecord);
- if (sourceRecord != null) {
- if (requestCode >= 0 && !sourceRecord.finishing) {
- resultRecord = sourceRecord;
- }
- }
- }
- final int launchFlags = intent.getFlags();
- if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
- // Transfer the result target from the source activity to the new
- // one being started, including any failures.
- if (requestCode >= 0) {
- ActivityOptions.abort(options);
- return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
- }
- resultRecord = sourceRecord.resultTo;
- if (resultRecord != null && !resultRecord.isInStackLocked()) {
- resultRecord = null;
- }
- resultWho = sourceRecord.resultWho;
- requestCode = sourceRecord.requestCode;
- sourceRecord.resultTo = null;
- if (resultRecord != null) {
- resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
- }
- if (sourceRecord.launchedFromUid == callingUid) {
- // The new activity is being launched from the same uid as the previous
- // activity in the flow, and asking to forward its result back to the
- // previous. In this case the activity is serving as a trampoline between
- // the two, so we also want to update its launchedFromPackage to be the
- // same as the previous activity. Note that this is safe, since we know
- // these two packages come from the same uid; the caller could just as
- // well have supplied that same package name itself. This specifially
- // deals with the case of an intent picker/chooser being launched in the app
- // flow to redirect to an activity picked by the user, where we want the final
- // activity to consider it to have been launched by the previous app activity.
- callingPackage = sourceRecord.launchedFromPackage;
- }
- }
- if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
- // We couldn't find a class that can handle the given Intent.
- // That's the end of that!
- err = ActivityManager.START_INTENT_NOT_RESOLVED;
- }
- if (err == ActivityManager.START_SUCCESS && aInfo == null) {
- // We couldn't find the specific class specified in the Intent.
- // Also the end of the line.
- err = ActivityManager.START_CLASS_NOT_FOUND;
- }
- if (err == ActivityManager.START_SUCCESS
- && !isCurrentProfileLocked(userId)
- && (aInfo.flags & FLAG_SHOW_FOR_ALL_USERS) == 0) {
- // Trying to launch a background activity that doesn't show for all users.
- err = ActivityManager.START_NOT_CURRENT_USER_ACTIVITY;
- }
- if (err == ActivityManager.START_SUCCESS && sourceRecord != null
- && sourceRecord.task.voiceSession != null) {
- // If this activity is being launched as part of a voice session, we need
- // to ensure that it is safe to do so. If the upcoming activity will also
- // be part of the voice session, we can only launch it if it has explicitly
- // said it supports the VOICE category, or it is a part of the calling app.
- if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
- && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
- try {
- intent.addCategory(Intent.CATEGORY_VOICE);
- if (!AppGlobals.getPackageManager().activitySupportsIntent(
- intent.getComponent(), intent, resolvedType)) {
- Slog.w(TAG,
- "Activity being started in current voice task does not support voice: "
- + intent);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure checking voice capabilities", e);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- }
- }
- if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
- // If the caller is starting a new voice session, just make sure the target
- // is actually allowing it to run this way.
- try {
- if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
- intent, resolvedType)) {
- Slog.w(TAG,
- "Activity being started in new voice task does not support: "
- + intent);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure checking voice capabilities", e);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- }
- final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
- if (err != ActivityManager.START_SUCCESS) {
- if (resultRecord != null) {
- resultStack.sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- ActivityOptions.abort(options);
- return err;
- }
- boolean abort = false;
- final int startAnyPerm = mService.checkPermission(
- START_ANY_ACTIVITY, callingPid, callingUid);
- if (startAnyPerm != PERMISSION_GRANTED) {
- final int componentRestriction = getComponentRestrictionForCallingPackage(
- aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
- final int actionRestriction = getActionRestrictionForCallingPackage(
- intent.getAction(), callingPackage, callingPid, callingUid);
- if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION
- || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
- if (resultRecord != null) {
- resultStack.sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- String msg;
- if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
- msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")" + " with revoked permission "
- + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
- } else if (!aInfo.exported) {
- msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " not exported from uid " + aInfo.applicationInfo.uid;
- } else {
- msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " requires " + aInfo.permission;
- }
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) {
- String message = "Appop Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " requires " + AppOpsManager.permissionToOp(
- ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()));
- Slog.w(TAG, message);
- abort = true;
- } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) {
- String message = "Appop Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission);
- Slog.w(TAG, message);
- abort = true;
- }
- }
- abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
- callingPid, resolvedType, aInfo.applicationInfo);
- if (mService.mController != null) {
- try {
- // The Intent we give to the watcher has the extra data
- // stripped off, since it can contain private information.
- Intent watchIntent = intent.cloneFilter();
- abort |= !mService.mController.activityStarting(watchIntent,
- aInfo.applicationInfo.packageName);
- } catch (RemoteException e) {
- mService.mController = null;
- }
- }
- if (abort) {
- if (resultRecord != null) {
- resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- // We pretend to the caller that it was really started, but
- // they will just get a cancel result.
- ActivityOptions.abort(options);
- return ActivityManager.START_SUCCESS;
- }
- ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
- intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
- requestCode, componentSpecified, voiceSession != null, this, container, options);
- if (outActivity != null) {
- outActivity[0] = r;
- }
- if (r.appTimeTracker == null && sourceRecord != null) {
- // If the caller didn't specify an explicit time tracker, we want to continue
- // tracking under any it has.
- r.appTimeTracker = sourceRecord.appTimeTracker;
- }
- final ActivityStack stack = mFocusedStack;
- if (voiceSession == null && (stack.mResumedActivity == null
- || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
- if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
- realCallingPid, realCallingUid, "Activity start")) {
- PendingActivityLaunch pal =
- new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
- mPendingActivityLaunches.add(pal);
- ActivityOptions.abort(options);
- return ActivityManager.START_SWITCHES_CANCELED;
- }
- }
- if (mService.mDidAppSwitch) {
- // This is the second allowed switch since we stopped switches,
- // so now just generally allow switches. Use case: user presses
- // home (switches disabled, switch to home, mDidAppSwitch now true);
- // user taps a home icon (coming from home so allowed, we hit here
- // and now allow anyone to switch again).
- mService.mAppSwitchesAllowedTime = 0;
- } else {
- mService.mDidAppSwitch = true;
- }
- doPendingActivityLaunchesLocked(false);
- err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
- startFlags, true, options, inTask);
- if (err < 0) {
- // If someone asked to have the keyguard dismissed on the next
- // activity start, but we are not actually doing an activity
- // switch... just dismiss the keyguard now, because we
- // probably want to see whatever is behind it.
- notifyActivityDrawnForKeyguard();
- }
- return err;
- }
startActivityLocked
@Step1:首先判断调用者本身的进场是否存在?否则就返回
- err = ActivityManager.START_PERMISSION_DENIED;
这种情况是存在的:调用者被系统杀死或者异常退出等。
@Step2:
- Intent.FLAG_ACTIVITY_FORWARD_RESULT
考虑这个传递标志,如果Activity1 启动了Actvitiy2,然后Activity2 启动了Activity3,当Activity3 调用SetResult以后,AMS会把Activity3 的result
传递给Activity1.
这是怎么做的的呢?
在启动Activity3的时候,我们把caller改为Activity1.
- if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
- // Transfer the result target from the source activity to the new
- // one being started, including any failures.
- if (requestCode >= 0) {
- ActivityOptions.abort(options);
- return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
- }
- resultRecord = sourceRecord.resultTo;
- if (resultRecord != null && !resultRecord.isInStackLocked()) {
- resultRecord = null;
- }
- resultWho = sourceRecord.resultWho;
- requestCode = sourceRecord.requestCode;
- sourceRecord.resultTo = null;
- if (resultRecord != null) {
- resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
- }
- if (sourceRecord.launchedFromUid == callingUid) {
- // The new activity is being launched from the same uid as the previous
- // activity in the flow, and asking to forward its result back to the
- // previous. In this case the activity is serving as a trampoline between
- // the two, so we also want to update its launchedFromPackage to be the
- // same as the previous activity. Note that this is safe, since we know
- // these two packages come from the same uid; the caller could just as
- // well have supplied that same package name itself. This specifially
- // deals with the case of an intent picker/chooser being launched in the app
- // flow to redirect to an activity picked by the user, where we want the final
- // activity to consider it to have been launched by the previous app activity.
- callingPackage = sourceRecord.launchedFromPackage;
- }
- }
因为Activity2 已经把接收result的对象设置为Activity1,所以Activity2 不能startactivityforresult去启动activity3.
@Step3:
没有合适的Component或者ActivityInfo为空,代码直接报错返回。
@Step4:
检查权限。
@Step5:
生成ActivityRecord r,用来记录各项判断的结果。
做完这些了以后,调用startActivityUncheckedLocked
startActivityUncheckedLocked会调用ActivityStack里面的startActivityLocked
startActivityLocked
先判断Intent.FLAG_ACTIVITY_NEW_TASK, 并确定为newTask。
然后把newTask = true。传入startActivityLocked。
- 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);
- mWindowManager.moveTaskToTop(taskId);
- }
查找task,并发task move to Top。
如果不是newTask,mTaskHistory里面找到它。
找到以后就干了几件事:
- task.addActivityToTop(r);
- r.putInHistory();
- mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
- r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
- r.userId, r.info.configChanges, task.voiceSession != null,
- r.mLaunchTaskBehind);
把Activity r 放到栈的最上面。
ActivityTask
Task是google专门为Android创造的一个概念。
关于launchmode & taskAffinity 可以看我的一篇博客。是以前对于Task & Intent这块的一个PPT。Android四大组件之Intent
这里我们分析下,google是怎么来实现这个概念的。
关于task的概念在上面的函数startActivityUncheckedLocked里面有讲到:
- int launchFlags = intent.getFlags();
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
(launchSingleInstance || launchSingleTask)) {
// We have a conflict between the Intent and the Activity manifest, manifest wins.
Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
"\"singleInstance\" or \"singleTask\"");
launchFlags &=
~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
} else {
switch (r.info.documentLaunchMode) {
case ActivityInfo.DOCUMENT_LAUNCH_NONE:
break;
case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
break;
case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
break;
case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
break;
}
}
这段开始就讲到launchmode的。
首先就是,判断是不是launchSingleTask 或者launchSingleInstance 是的化,就忽略FLAG_ACTIVITY_NEW_DOCUMENT这个属性。
不是这2个launchmode,就去判断documentLaunchMode的属性。
- final boolean launchTaskBehind = r.mLaunchTaskBehind
- && !launchSingleTask && !launchSingleInstance
- && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
- if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0
- && r.resultTo.task.stack != null) {
- // For whatever reason this activity is being launched into a new
- // task... yet the caller has requested a result back. Well, that
- // is pretty messed up, so instead immediately send back a cancel
- // and let the new task continue launched as normal without a
- // dependency on its originator.
- Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
- r.resultTo.task.stack.sendActivityResultLocked(-1,
- r.resultTo, r.resultWho, r.requestCode,
- Activity.RESULT_CANCELED, null);
- r.resultTo = null;
- }
判断activity是不是要重新开一个task,如果是的话,就把result去掉,应为在一个new task里面,必定是创建新的activity,所以也就么有传递result的必要。
- if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
- }
- // If we are actually going to launch in to a new task, there are some cases where
- // we further want to do multiple task.
- if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- if (launchTaskBehind
- || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
- launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
- }
- }
这个FLAG_ACTIVITY_MULTIPLE_TASK,是和Intent.FLAG_ACTIVITY_NEW_TASK一起使用,系统总是启动一个新task来启动activity
- ActivityRecord notTop =
- (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
- if (sourceRecord == null && inTask != null && inTask.stack != null) {
- final Intent baseIntent = inTask.getBaseIntent();
- final ActivityRecord root = inTask.getRootActivity();
- if (baseIntent == null) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Launching into task without base intent: "
- + inTask);
- }
- // If this task is empty, then we are adding the first activity -- it
- // determines the root, and must be launching as a NEW_TASK.
- if (launchSingleInstance || launchSingleTask) {
- if (!baseIntent.getComponent().equals(r.intent.getComponent())) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Trying to launch singleInstance/Task "
- + r + " into different task " + inTask);
- }
- if (root != null) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Caller with inTask " + inTask
- + " has root " + root + " but target is singleInstance/Task");
- }
- }
- // If task is empty, then adopt the interesting intent launch flags in to the
- // activity being started.
- if (root == null) {
- final int flagsOfInterest = Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
- | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
- launchFlags = (launchFlags&~flagsOfInterest)
- | (baseIntent.getFlags()&flagsOfInterest);
- intent.setFlags(launchFlags);
- inTask.setIntent(r);
- addingToTask = true;
- // If the task is not empty and the caller is asking to start it as the root
- // of a new task, then we don't actually want to start this on the task. We
- // will bring the task to the front, and possibly give it a new intent.
- } else if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- addingToTask = false;
- } else {
- addingToTask = true;
- }
- reuseTask = inTask;
- } else {
- inTask = null;
- }
- if (inTask == null) {
- if (sourceRecord == null) {
- // This activity is not being started from another... in this
- // case we -always- start a new task.
- if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
- Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
- "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
- }
- } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- // The original activity who is starting us is running as a single
- // instance... this new activity it is starting must go on its
- // own task.
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
- } else if (launchSingleInstance || launchSingleTask) {
- // The activity being started is a single instance... it always
- // gets launched into its own task.
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
- }
- }
我们来观察下singletask的套路:
- // If the caller is not coming from another activity, but has given us an
- // explicit task into which they would like us to launch the new activity,
- // then let's see about doing that.
- if (sourceRecord == null && inTask != null && inTask.stack != null) {
- final Intent baseIntent = inTask.getBaseIntent();
- final ActivityRecord root = inTask.getRootActivity();
- if (baseIntent == null) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Launching into task without base intent: "
- + inTask);
- }
- // If this task is empty, then we are adding the first activity -- it
- // determines the root, and must be launching as a NEW_TASK.
- if (launchSingleInstance || launchSingleTask) {
- if (!baseIntent.getComponent().equals(r.intent.getComponent())) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Trying to launch singleInstance/Task "
- + r + " into different task " + inTask);
- }
- if (root != null) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Caller with inTask " + inTask
- + " has root " + root + " but target is singleInstance/Task");
- }
- }
- // If task is empty, then adopt the interesting intent launch flags in to the
- // activity being started.
- if (root == null) {
- final int flagsOfInterest = Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
- | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
- launchFlags = (launchFlags&~flagsOfInterest)
- | (baseIntent.getFlags()&flagsOfInterest);
- intent.setFlags(launchFlags);
- inTask.setIntent(r);
- addingToTask = true;
- // If the task is not empty and the caller is asking to start it as the root
- // of a new task, then we don't actually want to start this on the task. We
- // will bring the task to the front, and possibly give it a new intent.
- } else if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- addingToTask = false;
- } else {
- addingToTask = true;
- }
- reuseTask = inTask;
- } else {
- inTask = null;
- }
如果task原来就是空的,哪就是添加root activity,所以要设置NEW_TASK这个标志位。
如果task已经存在,并且activity是root,我们不需要重新start newtask,只需要把这个task从新放到front就可以。
下面判断singletask & singleinstance标志位。如果sourceRecord是正在finishing的activity,我们不能在把它当做启动的源。
如果是singleinstance被拉到前台,由于它在task里面,“有且只有”它一个activity。找到它,并且movetofront。
然后判断topactivity,以及singletop launchmode。如果都满足,就把这个task启动起来,
android activity 管理器AMS----概述的更多相关文章
- Android布局管理器-使用LinearLayout实现简单的登录窗口布局
场景 Android布局管理器-从实例入手学习相对布局管理器的使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1038389 ...
- Android布局管理器-使用TableLayout表格布局管理器实现简单的用户登录页面
场景 Android布局管理器-使用FrameLayout帧布局管理器显示层叠的正方形以及前景照片: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article ...
- Android布局管理器-使用FrameLayout帧布局管理器显示层叠的正方形以及前景照片
场景 Android布局管理器-使用LinearLayout实现简单的登录窗口布局: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details ...
- android开发4:Android布局管理器1(线性布局,相对布局RelativeLayout-案例)
控件类概述 View 可视化控件的基类 属性名称 对应方法 描述 android:background setBackgroundResource(int) 设置背景 android:clickabl ...
- [置顶] Android布局管理器 - 详细解析布局实现
布局管理器都是以ViewGroup为基类派生出来的; 使用布局管理器可以适配不同手机屏幕的分辨率,尺寸大小; 布局管理器之间的继承关系 : 在上面的UML图中可以看出, 绝对布局 帧布局 网格布局 相 ...
- Android 布局管理器
为了更好地管理Android应用程序的用户界面组件,Android它提供了一个布局管理.通过使用布局管理,Android具有良好的平台无关的图形用户界面应用程序. 平时,推荐布局管理器来管理分布式组件 ...
- Android布局管理器(线性布局)
线性布局有LinearLayout类来代表,Android的线性布局和Swing的Box有点相似(他们都会将容器里面的组件一个接一个的排列起来),LinearLayout中,使用android:ori ...
- Android布局管理器(表格布局)
表格布局有TableLayout所代表,TableLayout继承了LinearLayout,因此他的本质依然是LinearLayout. 表格布局采用行.列的形式来进行管理,在使用的时候不需要声明多 ...
- Android 音频管理器AudioManager
音频管理器AudioManager,通过它可以管理android系统的音量或直接让系统静音,依旧是通过调用getSystemService()方法获取音频管理器AudioManager对象,获取到该对 ...
随机推荐
- Android manifest之系统自带的permission
Android manifest之系统自带的permission 本文描述Android系统自带的permission.点击查看:“关于permission的原始定义和说明”.点击查看:“Androi ...
- 【转载】利用shell脚本获取一个文件的绝对路径readlink
转载自:http://os.chinaunix.net/a2007/1118/976/000000976787.shtml #! /bin/bash echo "Path to $(base ...
- [git]解决:git config --global push.default matching
解决:git config --global push.default matching 这个警告的意思是:需要设置默认push的分支,所以设置好全局push的默认分支就好了.命令如下: 在有git目 ...
- Python内置模块(2)
这一部分主要介绍sys.os.hashlib和re模块.其中的re模块介绍得非常详细,是本部分的重点! 均为python3.5.1环境. 一.sys模块 sys模块涉及的主要是与python解释器相关 ...
- iOS实现图像指定区域模糊
在大多图像处理中,我们会应用到高斯模糊处理图像,通常用它来减少图像噪声以及降低细节层次.在此文中介绍了高斯模糊的实现和可选区域的模糊[美图秀秀-背景虚化] 高斯模糊的原理中,它是根据高斯曲线调节像素色 ...
- GPUImage滤镜之锐化
应用锐化工具可以快速聚焦模糊边缘,提高图像中某一部位的清晰度或者焦距程度,使图像特定区域的色彩更加鲜明. 在应用锐化工具时,若勾选器选项栏中的“对所有图层取样”复选框,则可对所有可见图层中的图像进行锐 ...
- Sprint 3计划
一.计划目标: 1.完成基本的首页面的信息查询功能 2.学生家教用户注册和登录,将信息存储到数据库 3.完成家教的资格评定设定和个人教学内容备份信息 二.燃尽图 三.项目具体工作细则 待明天工作会议分 ...
- WinForm输入网址打开源码
无聊练习一下WinForm,输入网址,点击按钮就在浏览器打开网址. 源代码下载: http://hovertree.com/h/bjaf/cao15h74.htm
- gitbook使用
第一步:安装node.js 官方网址:https://nodejs.org/en/ 运行以下命令,确认是否安装成功 node -v 第二步:安装gitbook npm install -g gitbo ...
- VS "15" 预览 5 中 VB 15 新增的功能
VS "15" 预览 5 给 VB 带来了更新.这次的更新内容有3个: * 值元组 ValueTuple这个功能能把一组计算结果成组返回.为了使用这个功能,我们要安装 System ...