美文网首页
Activity->02Token

Activity->02Token

作者: 冉桓彬 | 来源:发表于2019-05-23 18:40 被阅读0次

    Dialog会使用Activity的Token, View绘制时也会用到Activity.Token, 但是Token到底是个什么鬼?

    从点击桌面图片为切入点开始进行分析, 有一些代码细节全部省略

    一、Launcher进程

    方法调用链如下:

    Launcher.onClick
    Launcher.startActivitySafely
    Launcher.startActivity
    Instrumentation.execStartActivity
    ActivityManagerNative.getDefault().startActivity
    ActivityManagerProxy.startActivity
    BinderProxy. transact
    

    二、system_server进程

    方法调用链如下:

    ActivityManagerService.onTransact
    ActivityManagerService.startActivity
    ActivityStackSupervisor.startActivityMayWait
    ActivityStackSupervisor.startActivityLocked
        ActivityRecord r = new ActivityRecord;
        ActivityRecord.appToken = new Token;
    ----这里进行了ActivityRecord的创建以及Token的创建
    
    2.1 ActivityStackSupervisor.startActivityLocked
    final int startActivityLocked(IApplicationThread caller,
                Intent intent, String resolvedType, ActivityInfo aInfo,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                IBinder resultTo, String resultWho, int requestCode,
                int callingPid, int callingUid, String callingPackage,
                int realCallingPid, int realCallingUid, int startFlags, Bundle options,
                boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
                ActivityContainer container, TaskRecord inTask) {
            int err = ActivityManager.START_SUCCESS;
    
            ProcessRecord callerApp = null;
            if (caller != null) {
                callerApp = mService.getRecordForAppLocked(caller);
                if (callerApp != null) {
                    callingPid = callerApp.pid;
                    callingUid = callerApp.info.uid;
                } else {
                    ...
                }
            }
    
            final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
    
    
            ActivityRecord sourceRecord = null;
            ActivityRecord resultRecord = null;
            if (resultTo != null) {
                sourceRecord = isInAnyStackLocked(resultTo);
                if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                        "Will send result to " + resultTo + " " + sourceRecord);
                if (sourceRecord != null) {
                    if (requestCode >= 0 && !sourceRecord.finishing) {
                        resultRecord = sourceRecord;
                    }
                }
            }
    
            final int launchFlags = intent.getFlags();
    
            if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
                // Transfer the result target from the source activity to the new
                // one being started, including any failures.
                if (requestCode >= 0) {
                    ActivityOptions.abort(options);
                    return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
                }
                resultRecord = sourceRecord.resultTo;
                if (resultRecord != null && !resultRecord.isInStackLocked()) {
                    resultRecord = null;
                }
                resultWho = sourceRecord.resultWho;
                requestCode = sourceRecord.requestCode;
                sourceRecord.resultTo = null;
                if (resultRecord != null) {
                    resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
                }
                if (sourceRecord.launchedFromUid == callingUid) {
                    // The new activity is being launched from the same uid as the previous
                    // activity in the flow, and asking to forward its result back to the
                    // previous.  In this case the activity is serving as a trampoline between
                    // the two, so we also want to update its launchedFromPackage to be the
                    // same as the previous activity.  Note that this is safe, since we know
                    // these two packages come from the same uid; the caller could just as
                    // well have supplied that same package name itself.  This specifially
                    // deals with the case of an intent picker/chooser being launched in the app
                    // flow to redirect to an activity picked by the user, where we want the final
                    // activity to consider it to have been launched by the previous app activity.
                    callingPackage = sourceRecord.launchedFromPackage;
                }
            }
    
            final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
    
            if (err != ActivityManager.START_SUCCESS) {
                if (resultRecord != null) {
                    resultStack.sendActivityResultLocked(-1,
                        resultRecord, resultWho, requestCode,
                        Activity.RESULT_CANCELED, null);
                }
                ActivityOptions.abort(options);
                return err;
            }
    
            boolean abort = false;
    
            final int startAnyPerm = mService.checkPermission(
                    START_ANY_ACTIVITY, callingPid, callingUid);
    
           
    
            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, 其中aInfo以及Intent对应的是目标Activity相关的信息.
            ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                    intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                    requestCode, componentSpecified, voiceSession != null, this, container, options);
            if (outActivity != null) {
                outActivity[0] = r;
            }
    
            if (r.appTimeTracker == null && sourceRecord != null) {
                // If the caller didn't specify an explicit time tracker, we want to continue
                // tracking under any it has.
                r.appTimeTracker = sourceRecord.appTimeTracker;
            }
    
            final ActivityStack stack = mFocusedStack;
            if (voiceSession == null && (stack.mResumedActivity == null
                    || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
                if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                        realCallingPid, realCallingUid, "Activity start")) {
                    PendingActivityLaunch pal =
                            new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
                    mPendingActivityLaunches.add(pal);
                    ActivityOptions.abort(options);
                    return ActivityManager.START_SWITCHES_CANCELED;
                }
            }
            doPendingActivityLaunchesLocked(false);
    
            err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, true, options, inTask);
            return err;
    }
    

    小节: 启动Activity时, 如果需要新创建一个Activity, 则会为其创建一个ActivityRecord, 所以ActivityRecord与Activity是1v1的关系, 而ActivityRecord又是在system_server进程中, 他是如何与App进程中的目标Activity关联起来的?

    2.2 ActivityRecord初始化
    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
                int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
                ActivityInfo aInfo, Configuration _configuration,
                ActivityRecord _resultTo, String _resultWho, int _reqCode,
                boolean _componentSpecified, boolean _rootVoiceInteraction,
                ActivityStackSupervisor supervisor,
                ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
        service = _service;
        // 初始化Token
        appToken = new Token(this, service);
    }
    

    小节: 由于Activity与ActivityRecord是1v1的关系, 所以此时Token与Activity也是1v1的对应关系.

    2.3 ActivityStackSupervisor.realStartActivityLocked传入ActivityRecord.token
    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) {
        // app.thread指向ApplicationThreadProxy;
        // 传入ActivityRecord.appToken.
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                        new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                        task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                        newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
    }
    
    2.4 ApplicationThreadProxy.scheduleLaunchActivity将token写给App进程的目标Activity
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        intent.writeToParcel(data, 0);
        // 将token也就是目标Activity在system_server进程中的唯一标识写入到data中.
        data.writeStrongBinder(token);
            data.writeInt(ident);
            info.writeToParcel(data, 0);
            curConfig.writeToParcel(data, 0);
            if (overrideConfig != null) {
                data.writeInt(1);
                overrideConfig.writeToParcel(data, 0);
            } else {
                data.writeInt(0);
            }
            compatInfo.writeToParcel(data, 0);
            data.writeString(referrer);
            data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
            data.writeInt(procState);
            data.writeBundle(state);
            data.writePersistableBundle(persistentState);
            data.writeTypedList(pendingResults);
            data.writeTypedList(pendingNewIntents);
            data.writeInt(notResumed ? 1 : 0);
            data.writeInt(isForward ? 1 : 0);
            if (profilerInfo != null) {
                data.writeInt(1);
                profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
            } else {
                data.writeInt(0);
            }
        // data中是持有目标Activity的唯一标识Token.
        mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
        data.recycle();
    }
    

    小节: 通过mRemote也就是BinderProxy将数据写给App进程中的目标Activity, 然后触发App进程中的ApplicationThread.onTransact的执行

    三、App进程

    3.1 ApplicationThread.onTransact接收ApplicationThreadProxy.scheduleLaunchActivity写入的数据
    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
        switch (code) {
            case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION:
            {
                ...
                scheduleLaunchActivity(intent, b, ident, info, curConfig, overrideConfig, compatInfo,
                        referrer, voiceInteractor, procState, state, persistentState, ri, pi,
                        notResumed, isForward, profilerInfo);
                return true;
            }
        }
    }
    
    @Override
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                    ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                    CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                    int procState, Bundle state, PersistableBundle persistentState,
                    List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                    boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
    
        updateProcessState(procState, false);
        // App进程创建ActivityClientRecord, 对应system_server进程中的ActivityRecord.
        ActivityClientRecord r = new ActivityClientRecord();
        // 持有system_server进程中的token.
        r.token = token;
        r.ident = ident;
        r.intent = intent;
        r.referrer = referrer;
        r.voiceInteractor = voiceInteractor;
        r.activityInfo = info;
        r.compatInfo = compatInfo;
        r.state = state;
        r.persistentState = persistentState;
        r.pendingResults = pendingResults;
        r.pendingIntents = pendingNewIntents;
    
        r.startsNotResumed = notResumed;
        r.isForward = isForward;
    
        r.profilerInfo = profilerInfo;
    
        r.overrideConfig = overrideConfig;
        updatePendingConfiguration(curConfig);
        // 将ActivityClientRecord传给目标Activity.
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }
    

    小节: App进程创建ActivityClientRecord对应system_server进程中的ActivityRecord. 然后持有Token, 并通过Handler将Token传给目标Activity, 从而实现了system_server进程通过Token管理对应的Activity.

    3.2 ActivityThread.performLaunchActivity
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        Activity activity = null;
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        // 自此Token被传给了Activity
        activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
    }
    

    相关文章

      网友评论

          本文标题:Activity->02Token

          本文链接:https://www.haomeiwen.com/subject/ebvbzqtx.html