Activity启动详解

我们先从普通的应用内启动activity开始看起,也就是startActivity()这个方法,我们会发现这个函数最终会执行startActivityForResult()方法,传递的参数为intent和-1,所以我们直接看看这个函数

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) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

这个方法里面我们需要了解的mParent 这个变量,以及Instrumentation这个类,网上查了资料发现,mParent其实没什么用,而且一直为空,可能是被弃用了吧。所以这儿会执行mInstrumentation.execStartActivity() 这个方法

Instrumentation类是Android中的一个工具类,其实就是用监控activity性能等等的,一般用来做android的测试框架,我们接着在来看看Instrumentation中的execStartActivity()方法,我们看到传进去的参有contextThreadtoken,contextThread和token都是在ActivityThread调用attach方法时被赋值的,activity.attach()方法我在前面的《 ActivityManagerService启动解析》这篇文章中提到过,token我们可以理解为指向Ams的中当前acitvity的一个对象,我们可以用它来进行IPC调用。

Instrumentation源码位于/frameworks/base/core/java/android/app/Instrumentation.java。我们看看Instrumentation中的execStartActivity方法

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        ...
        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) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

在这里老点的adnroid源码和新的就有点区别了,我先讲API<26的这个版本的

API<26
————————————————————————————————————————————————
可以发现,这个方法是调用ActivityManagerNative.getDefault().startActivity这个方法,我们先来了解ActivityManagerNative,我们先看看下面张图,我在网上找的这里写图片描述

可以看到,ActivityManagerNative其实就是一个Binder通信类,通过他可以与AMS进行通信,ActivityManagerNative.getDefault()返回的是ActivityManagerProxy类,这里用到了代理模式,所以对ActivityManagerProxy的操作,实际是对ActivityManager的操作。

现在我们来梳理一下,ActivityManager是一个客户端,为了隔离它与ActivityManagerService,有效降低甚至消除二者的耦合度,在这中间使用了ActivityManagerProxy代理类,所有对ActivityManagerService的访问都转换成对代理类的访问,这样ActivityManager就与ActivityManagerService解耦了,并且ActivityManager客户端与ActivityManagerService服务端之间是通过binder机制来进行通信
————————————————————————————————————————————————

API>26
————————————————————————————————————————————————
但是在API>26源码中,已经不是调用ActivityManagerNative.getDefault().startActivity()方法,而是直接调用ActivityManager.getService() .startActivity()方法。但ActivityManagerNative.getDefault()和ActivityManager.getService()他们都是一样的,都是返回IActivityManager 方法,而且API>26的源码中ActivityManager与ActivityManagerService通过AIDL进行通信,我们看看这儿的源码

public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

在这里ServiceManager.getService(“activity”),通过ServiceManager的getService(“activity”)获取一个IBinder对象,获取到这个IBinder对象后调用了ActivityManagerNative的asInterface方法并传进去这个IBinder对象获得了一个IActivityManager对象,调用IActivityManager的startActivity()方法,其实就是调用AMS的startActivity()方法

在这里,补充一下,现在的android应用层实现都是通过AIDL实现binder,而不是以前的binder机制。现在我们接着看AMS中的startActivity方法,它的源码如下

public final int startActivity(IApplicationThread caller, String callingPackage,
           Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
           int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
       return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
               resultWho, requestCode, startFlags, profilerInfo, bOptions,
               UserHandle.getCallingUserId());
   }

这里就是调用了startActivityAsUser方法,我们接着看看ActivityStarter.startActivityAsUser

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }

这里继续调用mActivityStarter.startActivityMayWait,这里面涉及到一个ActivityStarter,这个类是在AMS构造函数里面new出来的,顾名思义,它其实就是activity的启动器,在前面的AMS启动解析中有讲过,我们接看看这个方法

final int startActivityMayWait(IApplicationThread caller,
        Intent intent, String resolvedType, Uri[] grantedUriPermissions,
        int grantedMode, IBinder resultTo,
        String resultWho, int requestCode, boolean onlyIfNeeded,
        boolean debug, WaitResult outResult, Configuration config) {

    intent = new Intent(intent);

    ResolveInfo rInfo =
        AppGlobals.getPackageManager().resolveIntent(
                intent, resolvedType,
                PackageManager.MATCH_DEFAULT_ONLY
                | ActivityManagerService.STOCK_PM_FLAGS);

    ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;

    if (aInfo != null) {
        intent.setComponent(new ComponentName(
                aInfo.applicationInfo.packageName, aInfo.name));
    }

    ..........

    int res = startActivityLocked(caller, intent, resolvedType,
                grantedUriPermissions, grantedMode, aInfo,
                resultTo, resultWho, requestCode, callingPid, callingUid,
                onlyIfNeeded, componentSpecified);

    .......... 

    return res;
}

这个方法比较长,精简下后,其实实际是通过resolveIntent找到匹配的Activity,然后调用startActivityLocked启动Activity,所以我们看看startActivityLocked,这个方法传入的参数如下
IApplicationThread caller:AActivity的进程内的ApplicationThread对象

  • Intent intent:要启动B的Intent

  • String resolvedType:BActivity的MIME TYPE

  • ActivityInfo aInfo:BActivity的ActivityInfo

  • IBinder resultTo:AActivity的token

  • String resultWho:AActivity的mEmbbedID,唯一标示这个Activity

  • int requestCode:startActivityForResult传入

  • int callingPid:调用者的PID

  • int callingUid:调用者的UID

  • int startFlags:0

  • Bundle options:由A传入的,一般为NULL

  • boolean componentSpecified:如果Intent的Component不为空的话,那么就为ture

    final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;

        //通过caller来得到ProcessReocrd对象,判断调用者进程是否存在,如果存在的话,那么将callingPid与callingUid重新赋值为ProcessRecord中的值
        _____________________________________________________________________________
        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 ? (mSupervisor.mFocusedStack == null ?
                    Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
                    (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
                            container.mActivityDisplay.mDisplayId)));
        }

        //声明了两个ActivityRecord引用,一个为sourceRecord,一个为resultRecord。sourceRecord代表着调用者的ActivityRecord,通过传入的token来得到的,此处就是AActivity的Record,而resultRecord只有在requestCode>1的时候才会被赋值为sourceRecord,否则就是null,可以看出,resultRecord是用来进行回调的,在BActivity中设置了setResult后,会通过resultRecord来传递result值
        _____________________________________________________________________________
        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = mSupervisor.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;
                }
            }
        }
        _____________________________________________________________________________
        //得到Intent的launchFlags,此时会判断launchFlags中是否有Intent.FLAG_ACTIVITY_FORWARD_RESULT,也就是重定向结果,因为Android允许将结果重定向,也就是A通过startActivityForResult启动B,而B可以通过startActivity,然后加入该标志位启动C,C调用setResult后,A就能的到C中的结果了。
        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;
            }
            //当launchFlags中有Intent.FLAG_ACTIVITY_FORWARD_RESULT的时候,判断requestCode是否大于等于0,如果大于等于0的话,那么就直接返回错误码了,因为B启动C的时候不允许通过startActivityForResult启动,如果是通过startActivity的话,那么就会执行如下代码
            _____________________________________________________________________________
            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 && 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 & 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 != START_SUCCESS) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(
                        -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
            }
            ActivityOptions.abort(options);
            return err;
        }
        //判断调用者是否有启动该Activity的权限
        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
                resultRecord, resultStack, options);
        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;
            }
        }

        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
        mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid,
                options);
        intent = mInterceptor.mIntent;
        rInfo = mInterceptor.mRInfo;
        aInfo = mInterceptor.mAInfo;
        resolvedType = mInterceptor.mResolvedType;
        inTask = mInterceptor.mInTask;
        callingPid = mInterceptor.mCallingPid;
        callingUid = mInterceptor.mCallingUid;
        options = mInterceptor.mActivityOptions;
        if (abort) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                        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 START_SUCCESS;
        }

        // If permissions need a review before any of the app components can run, we
        // launch the review activity and pass a pending intent to start the activity
        // we are to launching now after the review is completed.
        if ((mService.mPermissionReviewRequired
                || Build.PERMISSIONS_REVIEW_REQUIRED) && aInfo != null) {
            if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                    aInfo.packageName, userId)) {
                IIntentSender target = mService.getIntentSenderLocked(
                        ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                        callingUid, userId, null, null, 0, new Intent[]{intent},
                        new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
                                | PendingIntent.FLAG_ONE_SHOT, null);

                final int flags = intent.getFlags();
                Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
                newIntent.setFlags(flags
                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
                newIntent.putExtra(Intent.EXTRA_INTENT, new Inten
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值