zoukankan      html  css  js  c++  java
  • 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 的代码:

    frameworksaseservicesjavacomandroidserverSystemServera.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;
            }
        }
    View Code

    首先判断是不是显示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;
            }
    View Code

    如果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启动起来,

  • 相关阅读:
    触发Full GC执行的情况 以及其它补充信息
    HotSpot垃圾收集器GC的种类
    JVM学习之GC常用算法
    十大经典排序算法
    Java transient关键字使用
    Java并发编程:volatile关键字解析
    Linux Centos7.2 编译安装PHP7.0.2
    深入理解分布式事务及高并发下分布式事务的解决方案
    Windows及Linux环境搭建Redis集群
    软件项目进度管理(含敏捷项目管理)
  • 原文地址:https://www.cnblogs.com/deman/p/5004424.html
Copyright © 2011-2022 走看看