深入理解Activity——Token之旅

Token是ActivityRecord的内部静态类,我们先来看下Token的继承关系,Token extends IApplicationToken.Stub,从IApplicationToken.Stub类进行继承,根据Binder的机制可以知道Token是一个匿名Binder实体类,这个匿名Binder实体会传递给其他进程,其他进程会拿到Token的代理端。
    我们知道匿名Binder有两个比较重要的用途,一个是拿到Binder代理端后可跨Binder调用实体端的函数接口,另一个作用便是在多个进程中标识同一个对象。往往这两个作用是同时存在的,比如我们这里研究的Token就同时存在这两个作用,但最重要的便是后者,Token标识了一个ActivityRecord对象,即间接标识了一个Activity。
    下面这个图是Token的传递,首先会传递到WMS中,接着会传递到应用进程ActivityThread中,下面来具体分析这个传递流程。


1、Token对象的创建

        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, ActivityStackSupervisor supervisor,
                ActivityContainer container, Bundle options) {
            service = _service;
            appToken = new Token(this);
            ........
    }

在ActivityRecord的构造函数中创建,标识着当前这个ActivityRecord,即间接代表着一个Activity。

2、AMS调用WMS的addAPPToken()接口
在启动一个Activity时,会调用startActivityLocked()来在WMS中添加一个AppWindowToken对象;

        final void startActivityLocked(ActivityRecord r, boolean newTask,
                boolean doResume, boolean keepCurTransition, Bundle options) {
                ......
                mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                        r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                        (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
                        r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
                ......
        }


        public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
                int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
                int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
                ......
     
            synchronized(mWindowMap) {
                AppWindowToken atoken = findAppWindowToken(token.asBinder());
                if (atoken != null) {
                    Slog.w(TAG, "Attempted to add existing app token: " + token);
                    return;
                }
                atoken = new AppWindowToken(this, token, voiceInteraction);
                ......
                Task task = mTaskIdToTask.get(taskId);
                if (task == null) {
                    createTask(taskId, stackId, userId, atoken);
                } else {
                    task.addAppToken(addPos, atoken);
                }
                mTokenMap.put(token.asBinder(), atoken);
                // Application tokens start out hidden.
                atoken.hidden = true;
                atoken.hiddenRequested = true;
                //dump();
            }
        }


3、AMS跨Binder调用应用进程的scheduleLaunchActivity()将Token传递给上层应用进程

        final boolean realStartActivityLocked(ActivityRecord r,
                ProcessRecord app, boolean andResume, boolean checkConfig)
                throws RemoteException {
                ......
                app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                        r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
                        r.icicle, r.persistentState, results, newIntents, !andResume,
                        mService.isNextTransitionForward(), profilerInfo);
                ......
        }

这个是通过调用app.thread.scheduleLaunchActivity()完成的,可以知道对端接收到的便是Token的代理对象。
我们来看下ApplicationThread中scheduleLaunchActivity()的实现:

            public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                    ActivityInfo info, Configuration curConfig, 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);
                ActivityClientRecord r = new ActivityClientRecord();
                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;
                updatePendingConfiguration(curConfig);
                sendMessage(H.LAUNCH_ACTIVITY, r);
            }

函数中创建一个ActivityClientRecord对象,然后将Token的代理对象保存在ActivityClientRecord.token中。ActivityClientRecord也代表着一个Activity,不过是在应用进程中,而ActivityRecord是在ActivityManagerService中代表一个Activity。

4、Activity窗口添加
ViewRootImpl.setView()函数中添加Activity窗口时在参数mWindowAttributes中携带Token代理对象。

        public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
                if (mView == null) {
                    mView = view;
                    ......
                    mWindowAttributes.copyFrom(attrs);
                    ......
                    try {
                        ......
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(),
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
                    } catch (RemoteException e) {
                        ......
                    } finally {
                        ......
                    }
                ......
                }
            }
        }


        public int addWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
                ......
                boolean addToken = false;
                WindowToken token = mTokenMap.get(attrs.token);
                ......
                win = new WindowState(this, session, client, token,
                        attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
     
                mWindowMap.put(client.asBinder(), win);
                ......
        }

根据Binder机制可以知道从上层应用传递过来的Token代理对象会转换成SystemServer进程中的Token本地对象,后者与第2步中从Token对象是同一个对象,所以上面调用mTokenMap.get(attrs.token)时便能返回正确返回一个WindowToken(这个WindowToken其实是一个APPWindowToken),这样添加的窗口也就跟Activity关联上了。

---------------------
作者:高山流水29
来源:CSDN
原文:深入理解Activity——Token之旅_高山流水29的博客-CSDN博客_为什么activityrecord中要有token

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值