Android5.0 源码分析--- Launcher启动应用的过程

来源:互联网 发布:java方法重载例子 编辑:程序博客网 时间:2024/06/06 04:59

什么是Launcher?就是我们平常见到的桌面,在桌面上有许多的图标,点击图标后便会启动应用。
Launcher也是一个Activity
我们在5.0的源码包下发现了Luancher 2 和Luancher 3两个文件夹中均有Launcher.java这个文件
这里我们以Luancher 3为研究对象,来看Luancher是如何启动Activity的,首先我们进入到Luancher的点击事件中:

    public void onClick(View v) {        //............        Object tag = v.getTag();        if (tag instanceof ShortcutInfo) {            onClickAppShortcut(v);        } else if (tag instanceof FolderInfo) {            if (v instanceof FolderIcon) {                onClickFolderIcon(v);            }        } else if (v == mAllAppsButton) {            onClickAllAppsButton(v);        } else if (tag instanceof AppInfo) {            startAppShortcutOrInfoActivity(v);        } else if (tag instanceof LauncherAppWidgetInfo) {            if (v instanceof PendingAppWidgetHostView) {                onClickPendingWidget((PendingAppWidgetHostView) v);            }        }    }

相对于Android 2.0中的Luancher来说5.0中新增添了不少的花样,我们只用去关注它是如何启动我们应用就可以了,跟进每一个函数后我们会发现,要启动应用的核心函数是startAppShortcutOrInfoActivity:

    private void startAppShortcutOrInfoActivity(View v) {        Object tag = v.getTag();        final ShortcutInfo shortcut;        final Intent intent;        if (tag instanceof ShortcutInfo) {            shortcut = (ShortcutInfo) tag;            intent = shortcut.intent;            int[] pos = new int[2];            v.getLocationOnScreen(pos);            intent.setSourceBounds(new Rect(pos[0], pos[1],                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));        } else if (tag instanceof AppInfo) {            shortcut = null;            intent = ((AppInfo) tag).intent;        } else {            throw new IllegalArgumentException("Input must be a Shortcut or AppInfo");        }        boolean success = startActivitySafely(v, intent, tag);        mStats.recordLaunch(intent, shortcut);        if (success && v instanceof BubbleTextView) {            mWaitingForResume = (BubbleTextView) v;            mWaitingForResume.setStayPressed(true);        }    }

很明显我们在函数中是通过startActivitySafely这个函数来启动Activity

    boolean startActivitySafely(View v, Intent intent, Object tag) {        boolean success = false;        if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {            Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();            return false;        }        try {            success = startActivity(v, intent, tag);        } catch (ActivityNotFoundException e) {            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);        }        return success;    }

这里在前面做了一个小小的安全检查,两个字不管,继续到try cathch中,这里才是重要角色:

success = startActivity(v, intent, tag);

进入到startActivity中:

    public void startActivity(Intent intent) {        this.startActivity(intent, null);    }

再跟进:

    public void startActivity(Intent intent, @Nullable Bundle options) {        if (options != null) {            startActivityForResult(intent, -1, options);        } else {            // Note we want to go through this call for compatibility with            // applications that may have overridden the method.            startActivityForResult(intent, -1);        }    }

因为我们是启动应用所以不会有任何结果返回继而执行else中语句startActivityForResult:

    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {        if (mParent == null) {            Instrumentation.ActivityResult ar =                mInstrumentation.execStartActivity(                    this, mMainThread.getApplicationThread(), mToken, this,                    intent, requestCode, options);            if (ar != null) {                mMainThread.sendActivityResult(                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),                    ar.getResultData());            }            if (requestCode >= 0) {                mStartedActivity = true;            }            final View decor = mWindow != null ? mWindow.peekDecorView() : null;            if (decor != null) {                decor.cancelPendingInputEvents();            }        } else {            if (options != null) {                mParent.startActivityFromChild(this, intent, requestCode, options);            } else {                // Note we want to go through this method for compatibility with                // existing applications that may have overridden it.                mParent.startActivityFromChild(this, intent, requestCode);            }        }        if (options != null && !isTopOfTask()) {            mActivityTransitionState.startExitOutTransition(this, options);        }    }

着重看这一句:

            Instrumentation.ActivityResult ar =                mInstrumentation.execStartActivity(                    this, mMainThread.getApplicationThread(), mToken, this,                    intent, requestCode, options);

mInstrumentation它是一个Instrumentation的实例 主要的作用是Instrumentation是执行application instrumentation代码的基类。当应用程序运行的时候instrumentation处于开启,Instrumentation将在任何应用程序运行前初始化,可以通过它监测系统与应用程序之间的交互。一个应用程序中只有一个Instrumentation对象,每个Activity内部都有一个该对象的引用。Instrumentation可以理解为应用进程的管家, ActivityThread要创建或者暂停某 个 Activity时,是 通 过 这 个“ 管家” 进行的,设置这个管家的好处是可以统计所有的“ 开销”,开销的信息保存在“ 管家” 那里。其实正如其名称所示,Instrumentation就是为了 “测量”、 “统计”,因为管家掌握了所有的“ 开销”,自然也就具有了统计的功能。当然,Instrumentation类 和 ActivityThread的分工是有本质区别的,后者就像是这个家里的主人,负责创建这个“家庭”,并负责和外界打交道,比如 接 收AMS的通知等。
我们来看下execStartActivity中的实现:

    public ActivityResult execStartActivity(            Context who, IBinder contextThread, IBinder token, Activity target,            Intent intent, int requestCode, Bundle options) {        IApplicationThread whoThread = (IApplicationThread) contextThread;        //.......        try {            intent.migrateExtraStreamToClipData();            intent.prepareToLeaveProcess();            int result = ActivityManagerNative.getDefault()                .startActivity(whoThread, who.getBasePackageName(), intent,                        intent.resolveTypeIfNeeded(who.getContentResolver()),                        token, target != null ? target.mEmbeddedID : null,                        requestCode, 0, null, options);            checkStartActivityResult(result, intent);        } catch (RemoteException e) {        }        return null;    }

看一下传入的参数who 就是当前的上下文 第二个参数就是当前应用程序所在的主线程 第三个参数token是一个binder
execStartActivity主要是调用的

    int result = ActivityManagerNative.getDefault()                .startActivity(whoThread, who.getBasePackageName(), intent,                        intent.resolveTypeIfNeeded(who.getContentResolver()),                        token, target != null ? target.mEmbeddedID : null,                        requestCode, 0, null, options);

ActivityManagerNative.getDefault()方法返回一个ActivityManagerProxy对象调用了startActivity方法:
我们关注下其中一个参数:target.mEmbeddedID Intent-Filter中的有一个mimeType . 它的作用是告诉Android系统本Activity可以处理的文件的类型。如设置为 “text/plain”表示可以处理“.txt”文件。
如果没有那么就是null
我们在研究源码时一定要注意参数之间的相互传递,一定要做到心中有数,不然跟进几层后就晕头转向了。
下面看下ActivityManagerNative.getDefault().startActivity的实现:

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,            String resolvedType, IBinder resultTo, String resultWho, int requestCode,            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeInterfaceToken(IActivityManager.descriptor);        data.writeStrongBinder(caller != null ? caller.asBinder() : null);        data.writeString(callingPackage);        intent.writeToParcel(data, 0);        data.writeString(resolvedType);        data.writeStrongBinder(resultTo);        data.writeString(resultWho);        data.writeInt(requestCode);        data.writeInt(startFlags);        if (profilerInfo != null) {            data.writeInt(1);            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);        } else {            data.writeInt(0);        }        if (options != null) {            data.writeInt(1);            options.writeToParcel(data, 0);        } else {            data.writeInt(0);        }        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);        reply.readException();        int result = reply.readInt();        reply.recycle();        data.recycle();        return result;    }

很明显要和ActivityManagerNative通信肯定又要涉及到进程间的通信,我们在Pacel中准备了一些数据:
比如将intent写入到了Pacel data中,随后我们调用了

mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

显然我们就进入到了ActivityManagerService的startActivity函数来了:

    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());    }

跟进startActivityAsUser函数:

    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, userId, null, null);    }

我们可以看到的是在ActivityManagerService中有一个成员变量叫做mStackSupervisor 在Luancher3中它的类型是ActivityStackSupervisor,相对于过去的Luancher 2中的ActivityStack,做了一些变化,ActivityStackSupervisor 类是用来辅助管理ActivityStack的,里面有mHomeStack,mFocusedStack 和 mLastFocusedStack,它们的类型都是ActivityStack ,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, 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) {            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 = getFocusedStack();            } else {                stack = container.mStack;            }            stack.mConfigWillChange = config != null                    && mService.mConfiguration.diff(config) != 0;            if (DEBUG_CONFIGURATION) Slog.v(TAG,                    "Starting activity when config will change = " + stack.mConfigWillChange);            final long origId = Binder.clearCallingIdentity();            if (aInfo != null &&                    (aInfo.applicationInfo.flags&ApplicationInfo.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,                    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,                        "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 == ActivityState.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;        }    }

其中代码量比较大我们看关键的这一句:

                        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;                        }

其实就是解析Intent中的获取启动Activity的相关信息:
那么多下面就可以进入到

            int res = startActivityLocked(caller, intent, resolvedType, aInfo,                    voiceSession, voiceInteractor, resultTo, resultWho,                    requestCode, callingPid, callingUid, callingPackage,                    realCallingPid, realCallingUid, startFlags, options,                    componentSpecified, null, container, inTask);

跟进这个函数

    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 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;            }        }        if (err == ActivityManager.START_SUCCESS) {            final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;            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, "Will send result to " + resultTo + " " + sourceRecord);            if (sourceRecord != null) {                if (requestCode >= 0 && !sourceRecord.finishing) {                    resultRecord = sourceRecord;                }            }        }        ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;        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;            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 && 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 {                    if (!AppGlobals.getPackageManager().activitySupportsIntent(                            intent.getComponent(), intent, resolvedType)) {                        err = ActivityManager.START_NOT_VOICE_COMPATIBLE;                    }                } catch (RemoteException 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)) {                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;                }            } catch (RemoteException e) {                err = ActivityManager.START_NOT_VOICE_COMPATIBLE;            }        }        if (err != ActivityManager.START_SUCCESS) {            if (resultRecord != null) {                resultStack.sendActivityResultLocked(-1,                    resultRecord, resultWho, requestCode,                    Activity.RESULT_CANCELED, null);            }            ActivityOptions.abort(options);            return err;        }        final int startAnyPerm = mService.checkPermission(                START_ANY_ACTIVITY, callingPid, callingUid);        final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,                callingUid, aInfo.applicationInfo.uid, aInfo.exported);        if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) {            if (resultRecord != null) {                resultStack.sendActivityResultLocked(-1,                    resultRecord, resultWho, requestCode,                    Activity.RESULT_CANCELED, null);            }            String msg;            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);        }        boolean 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, this, container, options);        if (outActivity != null) {            outActivity[0] = r;        }        final ActivityStack stack = getFocusedStack();        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;    }

主要是检查目标APP或者Activity的一些信息,包括是否存在,是否拥有权限等
注意一下传入的参数:
从传进来的参数caller得到调用者的进程信息,并保存在callerApp变量中,这里就是Launcher应用程序的进程信息了。前面说过,参数resultTo是Launcher这个Activity里面的一个Binder对象,通过它可以获得Launcher这个Activity的相关信息,保存在sourceRecord变量中。
在这一步中:

        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,                requestCode, componentSpecified, this, container, options);

我们将Activity的信息记录下来 包括进程 intent等放入到ActivityRecord r中再调用

        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,                startFlags, true, options, inTask);

进入到startActivityUncheckedLocked中:

    final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,            boolean doResume, Bundle options, TaskRecord inTask) {        final Intent intent = r.intent;        final int callingUid = r.launchedFromUid;        // In some flows in to this function, we retrieve the task record and hold on to it        // without a lock before calling back in to here...  so the task at this point may        // not actually be in recents.  Check for that, and if it isn't in recents just        // consider it invalid.        if (inTask != null && !inTask.inRecents) {            Slog.w(TAG, "Starting activity in task not in recents: " + inTask);            inTask = null;        }        final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;        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;            }        }        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) {            // 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;        }        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;            }        }        // We'll invoke onUserLeaving before onPause only if the launching        // activity did not explicitly state that this is an automated launch.        mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;        if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);        // If the caller has asked not to resume at this point, we make note        // of this in the record so that we can skip it when trying to find        // the top running activity.        if (!doResume) {            r.delayedResume = true;        }        ActivityRecord notTop =                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;        // If the onlyIfNeeded flag is set, then we can do this if the activity        // being launched is the same as the one making the call...  or, as        // a special case, if we do not know the caller then we count the        // current top activity as the caller.        if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {            ActivityRecord checkedCaller = sourceRecord;            if (checkedCaller == null) {                checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop);            }            if (!checkedCaller.realActivity.equals(r.realActivity)) {                // Caller is not the same as launcher, so always needed.                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;            }        }        boolean addingToTask = false;        TaskRecord reuseTask = null;        // 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;        }        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;            }        }        ActivityInfo newTaskInfo = null;        Intent newTaskIntent = null;        ActivityStack sourceStack;        if (sourceRecord != null) {            if (sourceRecord.finishing) {                // If the source is finishing, we can't further count it as our source.  This                // is because the task it is associated with may now be empty and on its way out,                // so we don't want to blindly throw it in to that task.  Instead we will take                // the NEW_TASK flow and try to find a task for it. But save the task information                // so it can be used when creating the new task.                if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {                    Slog.w(TAG, "startActivity called from finishing " + sourceRecord                            + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;                    newTaskInfo = sourceRecord.info;                    newTaskIntent = sourceRecord.task.intent;                }                sourceRecord = null;                sourceStack = null;            } else {                sourceStack = sourceRecord.task.stack;            }        } else {            sourceStack = null;        }        boolean movedHome = false;        ActivityStack targetStack;        intent.setFlags(launchFlags);        // We may want to try to place the new activity in to an existing task.  We always        // do this if the target activity is singleTask or singleInstance; we will also do        // this if NEW_TASK has been requested, and there is not an additional qualifier telling        // us to still place it in a new task: multi task, always doc mode, or being asked to        // launch this as a new task behind the current one.        if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&                (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)                || launchSingleInstance || launchSingleTask) {            // If bring to front is requested, and no result is requested and we have not            // been given an explicit task to launch in to, and            // we can find a task that was started with this same            // component, then instead of launching bring that one to the front.            if (inTask == null && r.resultTo == null) {                // See if there is a task to bring to the front.  If this is                // a SINGLE_INSTANCE activity, there can be one and only one                // instance of it in the history, and it is always in its own                // unique task, so we do a special search.                ActivityRecord intentActivity = !launchSingleInstance ?                        findTaskLocked(r) : findActivityLocked(intent, r.info);                if (intentActivity != null) {                    if (isLockTaskModeViolation(intentActivity.task)) {                        showLockTaskToast();                        Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");                        return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;                    }                    if (r.task == null) {                        r.task = intentActivity.task;                    }                    targetStack = intentActivity.task.stack;                    targetStack.mLastPausedActivity = null;                    if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack                            + " from " + intentActivity);                    targetStack.moveToFront();                    if (intentActivity.task.intent == null) {                        // This task was started because of movement of                        // the activity based on affinity...  now that we                        // are actually launching it, we can assign the                        // base intent.                        intentActivity.task.setIntent(r);                    }                    // If the target task is not in the front, then we need                    // to bring it to the front...  except...  well, with                    // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like                    // to have the same behavior as if a new instance was                    // being started, which means not bringing it to the front                    // if the caller is not itself in the front.                    final ActivityStack lastStack = getLastStack();                    ActivityRecord curTop = lastStack == null?                            null : lastStack.topRunningNonDelayedActivityLocked(notTop);                    if (curTop != null && (curTop.task != intentActivity.task ||                            curTop.task != lastStack.topTask())) {                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);                        if (sourceRecord == null || (sourceStack.topActivity() != null &&                                sourceStack.topActivity().task == sourceRecord.task)) {                            // We really do want to push this one into the                            // user's face, right now.                            if (launchTaskBehind && sourceRecord != null) {                                intentActivity.setTaskToAffiliateWith(sourceRecord.task);                            }                            movedHome = true;                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);                            if ((launchFlags &                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {                                // Caller wants to appear on home activity.                                intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);                            }                            options = null;                        }                    }                    // If the caller has requested that the target task be                    // reset, then do so.                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {                        intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);                    }                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {                        // We don't need to start a new activity, and                        // the client said not to do anything if that                        // is the case, so this is it!  And for paranoia, make                        // sure we have correctly resumed the top activity.                        if (doResume) {                            resumeTopActivitiesLocked(targetStack, null, options);                        } else {                            ActivityOptions.abort(options);                        }                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;                    }                    if ((launchFlags &                            (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))                            == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {                        // The caller has requested to completely replace any                        // existing task with its new activity.  Well that should                        // not be too hard...                        reuseTask = intentActivity.task;                        reuseTask.performClearTaskLocked();                        reuseTask.setIntent(r);                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0                            || launchSingleInstance || launchSingleTask) {                        // In this situation we want to remove all activities                        // from the task up to the one being started.  In most                        // cases this means we are resetting the task to its                        // initial state.                        ActivityRecord top =                                intentActivity.task.performClearTaskLocked(r, launchFlags);                        if (top != null) {                            if (top.frontOfTask) {                                // Activity aliases may mean we use different                                // intents for the top activity, so make sure                                // the task now has the identity of the new                                // intent.                                top.task.setIntent(r);                            }                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,                                    r, top.task);                            top.deliverNewIntentLocked(callingUid, r.intent);                        } else {                            // A special case: we need to                            // start the activity because it is not currently                            // running, and the caller has asked to clear the                            // current task to have this activity at the top.                            addingToTask = true;                            // Now pretend like this activity is being started                            // by the top of its task, so it is put in the                            // right place.                            sourceRecord = intentActivity;                        }                    } else if (r.realActivity.equals(intentActivity.task.realActivity)) {                        // In this case the top activity on the task is the                        // same as the one being launched, so we take that                        // as a request to bring the task to the foreground.                        // If the top activity in the task is the root                        // activity, deliver this new intent to it if it                        // desires.                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)                                && intentActivity.realActivity.equals(r.realActivity)) {                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,                                    intentActivity.task);                            if (intentActivity.frontOfTask) {                                intentActivity.task.setIntent(r);                            }                            intentActivity.deliverNewIntentLocked(callingUid, r.intent);                        } else if (!r.intent.filterEquals(intentActivity.task.intent)) {                            // In this case we are launching the root activity                            // of the task, but with a different intent.  We                            // should start a new instance on top.                            addingToTask = true;                            sourceRecord = intentActivity;                        }                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {                        // In this case an activity is being launched in to an                        // existing task, without resetting that task.  This                        // is typically the situation of launching an activity                        // from a notification or shortcut.  We want to place                        // the new activity on top of the current task.                        addingToTask = true;                        sourceRecord = intentActivity;                    } else if (!intentActivity.task.rootWasReset) {                        // In this case we are launching in to an existing task                        // that has not yet been started from its front door.                        // The current task has been brought to the front.                        // Ideally, we'd probably like to place this new task                        // at the bottom of its stack, but that's a little hard                        // to do with the current organization of the code so                        // for now we'll just drop it.                        intentActivity.task.setIntent(r);                    }                    if (!addingToTask && reuseTask == null) {                        // We didn't do anything...  but it was needed (a.k.a., client                        // don't use that intent!)  And for paranoia, make                        // sure we have correctly resumed the top activity.                        if (doResume) {                            targetStack.resumeTopActivityLocked(null, options);                        } else {                            ActivityOptions.abort(options);                        }                        return ActivityManager.START_TASK_TO_FRONT;                    }                }            }        }        //String uri = r.intent.toURI();        //Intent intent2 = new Intent(uri);        //Slog.i(TAG, "Given intent: " + r.intent);        //Slog.i(TAG, "URI is: " + uri);        //Slog.i(TAG, "To intent: " + intent2);        if (r.packageName != null) {            // If the activity being launched is the same as the one currently            // at the top, then we need to check if it should only be launched            // once.            ActivityStack topStack = getFocusedStack();            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);            if (top != null && r.resultTo == null) {                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {                    if (top.app != null && top.app.thread != null) {                        if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0                            || launchSingleTop || launchSingleTask) {                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,                                    top.task);                            // For paranoia, make sure we have correctly                            // resumed the top activity.                            topStack.mLastPausedActivity = null;                            if (doResume) {                                resumeTopActivitiesLocked();                            }                            ActivityOptions.abort(options);                            if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {                                // We don't need to start a new activity, and                                // the client said not to do anything if that                                // is the case, so this is it!                                return ActivityManager.START_RETURN_INTENT_TO_CALLER;                            }                            top.deliverNewIntentLocked(callingUid, r.intent);                            return ActivityManager.START_DELIVERED_TO_TOP;                        }                    }                }            }        } else {            if (r.resultTo != null) {                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,                        r.requestCode, Activity.RESULT_CANCELED, null);            }            ActivityOptions.abort(options);            return ActivityManager.START_CLASS_NOT_FOUND;        }        boolean newTask = false;        boolean keepCurTransition = false;        TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?                sourceRecord.task : null;        // Should this be considered a new task?        if (r.resultTo == null && inTask == null && !addingToTask                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {            if (isLockTaskModeViolation(reuseTask)) {                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;            }            newTask = true;            targetStack = adjustStackFocus(r, newTask);            if (!launchTaskBehind) {                targetStack.moveToFront();            }            if (reuseTask == null) {                r.setTask(targetStack.createTaskRecord(getNextTaskId(),                        newTaskInfo != null ? newTaskInfo : r.info,                        newTaskIntent != null ? newTaskIntent : intent,                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),                        taskToAffiliate);                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +                        r.task);            } else {                r.setTask(reuseTask, taskToAffiliate);            }            if (!movedHome) {                if ((launchFlags &                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {                    // Caller wants to appear on home activity, so before starting                    // their own activity we will bring home to the front.                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);                }            }        } else if (sourceRecord != null) {            final TaskRecord sourceTask = sourceRecord.task;            if (isLockTaskModeViolation(sourceTask)) {                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;            }            targetStack = sourceTask.stack;            targetStack.moveToFront();            final TaskRecord topTask = targetStack.topTask();            if (topTask != sourceTask) {                targetStack.moveTaskToFrontLocked(sourceTask, r, options);            } else {                mWindowManager.moveTaskToTop(topTask.taskId);            }            if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {                // In this case, we are adding the activity to an existing                // task, but the caller has asked to clear that task if the                // activity is already running.                ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);                keepCurTransition = true;                if (top != null) {                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);                    top.deliverNewIntentLocked(callingUid, r.intent);                    // For paranoia, make sure we have correctly                    // resumed the top activity.                    targetStack.mLastPausedActivity = null;                    if (doResume) {                        targetStack.resumeTopActivityLocked(null);                    }                    ActivityOptions.abort(options);                    return ActivityManager.START_DELIVERED_TO_TOP;                }            } else if (!addingToTask &&                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {                // In this case, we are launching an activity in our own task                // that may already be running somewhere in the history, and                // we want to shuffle it to the front of the stack if so.                final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);                if (top != null) {                    final TaskRecord task = top.task;                    task.moveActivityToFrontLocked(top);                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);                    top.updateOptionsLocked(options);                    top.deliverNewIntentLocked(callingUid, r.intent);                    targetStack.mLastPausedActivity = null;                    if (doResume) {                        targetStack.resumeTopActivityLocked(null);                    }                    return ActivityManager.START_DELIVERED_TO_TOP;                }            }            // An existing activity is starting this new activity, so we want            // to keep the new one in the same task as the one that is starting            // it.            r.setTask(sourceTask, null);            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                    + " in existing task " + r.task + " from source " + sourceRecord);        } else if (inTask != null) {            // The calling is asking that the new activity be started in an explicit            // task it has provided to us.            if (isLockTaskModeViolation(inTask)) {                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;            }            targetStack = inTask.stack;            targetStack.moveTaskToFrontLocked(inTask, r, options);            targetStack.moveToFront();            mWindowManager.moveTaskToTop(inTask.taskId);            // Check whether we should actually launch the new activity in to the task,            // or just reuse the current activity on top.            ActivityRecord top = inTask.getTopActivity();            if (top != null && top.realActivity.equals(r.realActivity) && top.userId == r.userId) {                if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0                        || launchSingleTop || launchSingleTask) {                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {                        // We don't need to start a new activity, and                        // the client said not to do anything if that                        // is the case, so this is it!                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;                    }                    top.deliverNewIntentLocked(callingUid, r.intent);                    return ActivityManager.START_DELIVERED_TO_TOP;                }            }            if (!addingToTask) {                // We don't actually want to have this activity added to the task, so just                // stop here but still tell the caller that we consumed the intent.                ActivityOptions.abort(options);                return ActivityManager.START_TASK_TO_FRONT;            }            r.setTask(inTask, null);            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                    + " in explicit task " + r.task);        } else {            // This not being started from an existing activity, and not part            // of a new task...  just put it in the top task, though these days            // this case should never happen.            targetStack = adjustStackFocus(r, newTask);            targetStack.moveToFront();            ActivityRecord prev = targetStack.topActivity();            r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),                            r.info, intent, null, null, true), null);            mWindowManager.moveTaskToTop(r.task.taskId);            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                    + " in new guessed " + r.task);        }        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,                intent, r.getUriPermissionsLocked(), r.userId);        if (sourceRecord != null && sourceRecord.isRecentsActivity()) {            r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);        }        if (newTask) {            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);        }        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);        targetStack.mLastPausedActivity = null;        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);        if (!launchTaskBehind) {            // Don't set focus on an activity that's going to the back.            mService.setFocusedActivityLocked(r);        }        return ActivityManager.START_SUCCESS;    }

在这个函数中 我们先前传入了一个ActivityRecord r,Activity的信息都处于这里,我们这里首先拿出启动模式(一共有四种)

        final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;

在Android5.0 中加入了许多可以从最近任务启动的Activity的逻辑,后面的逻辑则是如何实现这四种启动方式的逻辑,相当复杂。那么接下来就是调用resumeTopActivityLocked()
这个函数主要是判断位于栈顶部的Activity是不是将要启动的Activity 如果是则什么都不做,如果不是就要将现在的这个Activity 推入Pause程序,以便新的Activity位于栈顶。
此时我们思考下,这个Activity就是Luancher 的Activity,我们显然他和我们现在并不在同一个进程之中,想要通知它进入Pause状态我们还是必须要进行进程间的通信。
在每个应用中都有一个主线程来负责UI的渲染之类的活动,那么我们拿到Luancher 这个Activity中的ApplicationThreadNative的接口ApplicationThreadProxy来执行其中的schedulePauseActivity方法:

    public final void schedulePauseActivity(IBinder token, boolean finished,            boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {        Parcel data = Parcel.obtain();        data.writeInterfaceToken(IApplicationThread.descriptor);        data.writeStrongBinder(token);        data.writeInt(finished ? 1 : 0);        data.writeInt(userLeaving ? 1 :0);        data.writeInt(configChanges);        data.writeInt(dontReport ? 1 : 0);        mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,                IBinder.FLAG_ONEWAY);        data.recycle();    }

实际上这里会进入到ApplicationThread这个类中的schedulePauseActivity

public final void schedulePauseActivity(IBinder token, boolean finished,                  boolean userLeaving, int configChanges) {              queueOrSendMessage(                  finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,                  token,                  (userLeaving ? 1 : 0),                  configChanges);          }  

进入到queueOrSendMessage函数中:
这里实际上是一个主线程中了,这个方法会发一个消息,这个消息有一个handler接收处理,在handler中会调用handlePauseActivity去处理这个Activity

    private void handlePauseActivity(IBinder token, boolean finished,            boolean userLeaving, int configChanges, boolean dontReport) {        ActivityClientRecord r = mActivities.get(token);        if (r != null) {            //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);            if (userLeaving) {                performUserLeavingActivity(r);            }            r.activity.mConfigChangeFlags |= configChanges;            performPauseActivity(token, finished, r.isPreHoneycomb());            // Make sure any pending writes are now committed.            if (r.isPreHoneycomb()) {                QueuedWork.waitToFinish();            }            // Tell the activity manager we have paused.            if (!dontReport) {                try {                    ActivityManagerNative.getDefault().activityPaused(token);                } catch (RemoteException ex) {                }            }            mSomeActivitiesChanged = true;        }    }

这里传入的token就是 Luancher Activity的信息,我们将Luancher Activity的这个信息取出,放入到ActivityClientRecord r
1.如果userLeaving为true,则通过调用performUserLeavingActivity函数来调用Activity.onUserLeaveHint通知Activity,用户要离开它了;
2.调用performPauseActivity函数来调用Activity.onPause函数,我们知道,在Activity的生命周期中,当它要让位于其它的Activity时,系统就会调用它的onPause函数;
3.它通知ActivityManagerService,这个Activity已经进入Paused状态了,ActivityManagerService现在可以完成未竟的事情,即启动MainActivity了。

ActivityManagerNative.getDefault().activityPaused(token);

最后的这里ActivityManagerProxy调用activityPaused,我们这里实际上会调用到的是ActivityManagerService中的activityPaused

    public final void activityPaused(IBinder token) {        final long origId = Binder.clearCallingIdentity();        synchronized(this) {            ActivityStack stack = ActivityRecord.getStackLocked(token);            if (stack != null) {                stack.activityPausedLocked(token, false);            }        }        Binder.restoreCallingIdentity(origId);    }

这里调用了ActivityStack 中的activityPausedLocked:

    final void activityPausedLocked(IBinder token, boolean timeout) {        if (DEBUG_PAUSE) Slog.v(            TAG, "Activity paused: token=" + token + ", timeout=" + timeout);        final ActivityRecord r = isInStackLocked(token);        if (r != null) {            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);            if (mPausingActivity == r) {                if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r                        + (timeout ? " (due to timeout)" : " (pause complete)"));                completePauseLocked(true);            } else {                EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,                        r.userId, System.identityHashCode(r), r.shortComponentName,                        mPausingActivity != null                            ? mPausingActivity.shortComponentName : "(none)");            }        }    }

跟进completePauseLocked:

    private void completePauseLocked(boolean resumeNext) {        ActivityRecord prev = mPausingActivity;        if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);        if (prev != null) {            prev.state = ActivityState.PAUSED;            if (prev.finishing) {                if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);            } else if (prev.app != null) {                if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);                if (prev.waitingVisible) {                    prev.waitingVisible = false;                    mStackSupervisor.mWaitingVisibleActivities.remove(prev);                    if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(                            TAG, "Complete pause, no longer waiting: " + prev);                }                if (prev.configDestroy) {                    // The previous is being paused because the configuration                    // is changing, which means it is actually stopping...                    // To juggle the fact that we are also starting a new                    // instance right now, we need to first completely stop                    // the current instance before starting the new one.                    if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);                    destroyActivityLocked(prev, true, "pause-config");                } else if (!hasVisibleBehindActivity()) {                    // If we were visible then resumeTopActivities will release resources before                    // stopping.                    mStackSupervisor.mStoppingActivities.add(prev);                    if (mStackSupervisor.mStoppingActivities.size() > 3 ||                            prev.frontOfTask && mTaskHistory.size() <= 1) {                        // If we already have a few activities waiting to stop,                        // then give up on things going idle and start clearing                        // them out. Or if r is the last of activity of the last task the stack                        // will be empty and must be cleared immediately.                        if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");                        mStackSupervisor.scheduleIdleLocked();                    } else {                        mStackSupervisor.checkReadyForSleepLocked();                    }                }            } else {                if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);                prev = null;            }            mPausingActivity = null;        }        if (resumeNext) {            final ActivityStack topStack = mStackSupervisor.getFocusedStack();            if (!mService.isSleepingOrShuttingDown()) {                mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);            } else {                mStackSupervisor.checkReadyForSleepLocked();                ActivityRecord top = topStack.topRunningActivityLocked(null);                if (top == null || (prev != null && top != prev)) {                    // If there are no more activities available to run,                    // do resume anyway to start something.  Also if the top                    // activity on the stack is not the just paused activity,                    // we need to go ahead and resume it to ensure we complete                    // an in-flight app switch.                    mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);                }            }        }        if (prev != null) {            prev.resumeKeyDispatchingLocked();            if (prev.app != null && prev.cpuTimeAtResume > 0                    && mService.mBatteryStatsService.isOnBattery()) {                long diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)                        - prev.cpuTimeAtResume;                if (diff > 0) {                    BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();                    synchronized (bsi) {                        BatteryStatsImpl.Uid.Proc ps =                                bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,                                        prev.info.packageName);                        if (ps != null) {                            ps.addForegroundTimeLocked(diff);                        }                    }                }            }            prev.cpuTimeAtResume = 0; // reset it        }    }

首先函数将mPausingActivity保存在prev中,为prev设置状态,最终调用 ActivityManagerService中的startProcessLocked函数中的Process.start接口来创建一个新的进程,新的进程会导入android.app.ActivityThread类,并且执行它的main函数,这就是为什么我们前面说每一个应用程序都有一个ActivityThread实例来对应的原因。
在ActivityThread中有一个performLaunchActivity这个方法:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")        ActivityInfo aInfo = r.activityInfo;        if (r.packageInfo == null) {            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,                    Context.CONTEXT_INCLUDE_CODE);        }        ComponentName component = r.intent.getComponent();        if (component == null) {            component = r.intent.resolveActivity(                mInitialApplication.getPackageManager());            r.intent.setComponent(component);        }        if (r.activityInfo.targetActivity != null) {            component = new ComponentName(r.activityInfo.packageName,                    r.activityInfo.targetActivity);        }     Activity activity = null;        try {            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();            activity = mInstrumentation.newActivity(                    cl, component.getClassName(), r.intent);            StrictMode.incrementExpectedActivityCount(activity.getClass());            r.intent.setExtrasClassLoader(cl);            r.intent.prepareToEnterProcess();            if (r.state != null) {                r.state.setClassLoader(cl);            }        } catch (Exception e) {            if (!mInstrumentation.onException(activity, e)) {                throw new RuntimeException(                    "Unable to instantiate activity " + component                    + ": " + e.toString(), e);            }        }        try {            Application app = r.packageInfo.makeApplication(false, mInstrumentation);            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);            if (localLOGV) Slog.v(                    TAG, r + ": app=" + app                    + ", appName=" + app.getPackageName()                    + ", pkg=" + r.packageInfo.getPackageName()                    + ", comp=" + r.intent.getComponent().toShortString()                    + ", dir=" + r.packageInfo.getAppDir());            if (activity != null) {                Context appContext = createBaseContextForActivity(r, activity);                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());                Configuration config = new Configuration(mCompatConfiguration);                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "                        + r.activityInfo.name + " with config " + config);                activity.attach(appContext, this, getInstrumentation(), r.token,                        r.ident, app, r.intent, r.activityInfo, title, r.parent,                        r.embeddedID, r.lastNonConfigurationInstances, config,                        r.voiceInteractor);                if (customIntent != null) {                    activity.mIntent = customIntent;                }                r.lastNonConfigurationInstances = null;                activity.mStartedActivity = false;                int theme = r.activityInfo.getThemeResource();                if (theme != 0) {                    activity.setTheme(theme);                }                activity.mCalled = false;                if (r.isPersistable()) {                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);                } else {                    mInstrumentation.callActivityOnCreate(activity, r.state);                }                if (!activity.mCalled) {                    throw new SuperNotCalledException(                        "Activity " + r.intent.getComponent().toShortString() +                        " did not call through to super.onCreate()");                }                r.activity = activity;                r.stopped = true;                if (!r.activity.mFinished) {                    activity.performStart();                    r.stopped = false;                }                if (!r.activity.mFinished) {                    if (r.isPersistable()) {                        if (r.state != null || r.persistentState != null) {                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,                                    r.persistentState);                        }                    } else if (r.state != null) {                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);                    }                }                if (!r.activity.mFinished) {                    activity.mCalled = false;                    if (r.isPersistable()) {                        mInstrumentation.callActivityOnPostCreate(activity, r.state,                                r.persistentState);                    } else {                        mInstrumentation.callActivityOnPostCreate(activity, r.state);                    }                    if (!activity.mCalled) {                        throw new SuperNotCalledException(                            "Activity " + r.intent.getComponent().toShortString() +                            " did not call through to super.onPostCreate()");                    }                }            }            r.paused = true;            mActivities.put(r.token, r);        } catch (SuperNotCalledException e) {            throw e;        } catch (Exception e) {            if (!mInstrumentation.onException(activity, e)) {                throw new RuntimeException(                    "Unable to start activity " + component                    + ": " + e.toString(), e);            }        }        return activity;    }

首先拿出packageInfo和Component的信息:

        ActivityInfo aInfo = r.activityInfo;        if (r.packageInfo == null) {            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,                    Context.CONTEXT_INCLUDE_CODE);        }        ComponentName component = r.intent.getComponent();        if (component == null) {            component = r.intent.resolveActivity(                mInitialApplication.getPackageManager());            r.intent.setComponent(component);        }        if (r.activityInfo.targetActivity != null) {            component = new ComponentName(r.activityInfo.packageName,                    r.activityInfo.targetActivity);        }

通过ClassLoader加载Activity类加载进来,最后通过mInstrumentation.newActivity初始化

        try {            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();            activity = mInstrumentation.newActivity(                    cl, component.getClassName(), r.intent);            StrictMode.incrementExpectedActivityCount(activity.getClass());            r.intent.setExtrasClassLoader(cl);            r.intent.prepareToEnterProcess();            if (r.state != null) {                r.state.setClassLoader(cl);            }        } catch (Exception e) {            if (!mInstrumentation.onException(activity, e)) {                throw new RuntimeException(                    "Unable to instantiate activity " + component                    + ": " + e.toString(), e);            }        }

初始化Application类,再初始化Activity上下文信息,最后调用mInstrumentation.callActivityOnPostCreate调用Oncreate方法。

0 0
原创粉丝点击