深入理解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对象的创建
[java]  view plain  copy
  1. ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,  
  2.         int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,  
  3.         ActivityInfo aInfo, Configuration _configuration,  
  4.         ActivityRecord _resultTo, String _resultWho, int _reqCode,  
  5.         boolean _componentSpecified, ActivityStackSupervisor supervisor,  
  6.         ActivityContainer container, Bundle options) {  
  7.     service = _service;  
  8.     appToken = new Token(this);  
  9.     ........  
在ActivityRecord的构造函数中创建,标识着当前这个ActivityRecord,即间接代表着一个Activity。

2、AMS调用WMS的addAPPToken()接口
在启动一个Activity时,会调用startActivityLocked()来在WMS中添加一个AppWindowToken对象;
[java]  view plain  copy
  1. final void startActivityLocked(ActivityRecord r, boolean newTask,  
  2.         boolean doResume, boolean keepCurTransition, Bundle options) {  
  3.         ......  
  4.         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,  
  5.                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,  
  6.                 (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,  
  7.                 r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);  
  8.         ......  
  9. }  

[java]  view plain  copy
  1. public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,  
  2.         int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,  
  3.         int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {  
  4.         ......  
  5.   
  6.     synchronized(mWindowMap) {  
  7.         AppWindowToken atoken = findAppWindowToken(token.asBinder());  
  8.         if (atoken != null) {  
  9.             Slog.w(TAG, "Attempted to add existing app token: " + token);  
  10.             return;  
  11.         }  
  12.         atoken = new AppWindowToken(this, token, voiceInteraction);  
  13.         ......  
  14.         Task task = mTaskIdToTask.get(taskId);  
  15.         if (task == null) {  
  16.             createTask(taskId, stackId, userId, atoken);  
  17.         } else {  
  18.             task.addAppToken(addPos, atoken);  
  19.         }  
  20.         mTokenMap.put(token.asBinder(), atoken);  
  21.         // Application tokens start out hidden.  
  22.         atoken.hidden = true;  
  23.         atoken.hiddenRequested = true;  
  24.         //dump();  
  25.     }  
  26. }  

3、AMS跨Binder调用应用进程的 scheduleLaunchActivity()将 Token传递给上层应用进程
[java]  view plain  copy
  1. final boolean realStartActivityLocked(ActivityRecord r,  
  2.         ProcessRecord app, boolean andResume, boolean checkConfig)  
  3.         throws RemoteException {  
  4.         ......  
  5.         app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,  
  6.                 System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),  
  7.                 r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,  
  8.                 r.icicle, r.persistentState, results, newIntents, !andResume,  
  9.                 mService.isNextTransitionForward(), profilerInfo);  
  10.         ......  
  11. }  
这个是通过调用app.thread.scheduleLaunchActivity()完成的,可以知道对端接收到的便是Token的代理对象。
我们来看下ApplicationThread中scheduleLaunchActivity()的实现:
[java]  view plain  copy
  1. public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,  
  2.         ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,  
  3.         String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,  
  4.         PersistableBundle persistentState, List<ResultInfo> pendingResults,  
  5.         List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,  
  6.         ProfilerInfo profilerInfo) {  
  7.     updateProcessState(procState, false);  
  8.     ActivityClientRecord r = new ActivityClientRecord();  
  9.     r.token = token;  
  10.     r.ident = ident;  
  11.     r.intent = intent;  
  12.     r.referrer = referrer;  
  13.     r.voiceInteractor = voiceInteractor;  
  14.     r.activityInfo = info;  
  15.     r.compatInfo = compatInfo;  
  16.     r.state = state;  
  17.     r.persistentState = persistentState;  
  18.     r.pendingResults = pendingResults;  
  19.     r.pendingIntents = pendingNewIntents;  
  20.     r.startsNotResumed = notResumed;  
  21.     r.isForward = isForward;  
  22.     r.profilerInfo = profilerInfo;  
  23.     updatePendingConfiguration(curConfig);  
  24.     sendMessage(H.LAUNCH_ACTIVITY, r);  
  25. }  
函数中创建一个ActivityClientRecord对象,然后将Token的代理对象保存在 ActivityClientRecord.token中。ActivityClientRecord也代表着一个Activity,不过是在应用进程中,而ActivityRecord是在ActivityManagerService中代表一个Activity。

4、Activity窗口添加
ViewRootImpl.setView()函数中添加Activity窗口时在参数mWindowAttributes中携带Token代理对象。
[java]  view plain  copy
  1. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
  2.     synchronized (this) {  
  3.         if (mView == null) {  
  4.             mView = view;  
  5.             ......  
  6.             mWindowAttributes.copyFrom(attrs);  
  7.             ......  
  8.             try {  
  9.                 ......  
  10.                 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,  
  11.                         getHostVisibility(), mDisplay.getDisplayId(),  
  12.                         mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);  
  13.             } catch (RemoteException e) {  
  14.                 ......  
  15.             } finally {  
  16.                 ......  
  17.             }  
  18.         ......  
  19.         }  
  20.     }  
  21. }  

[java]  view plain  copy
  1. public int addWindow(Session session, IWindow client, int seq,  
  2.         WindowManager.LayoutParams attrs, int viewVisibility, int displayId,  
  3.         Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {  
  4.         ......  
  5.         boolean addToken = false;  
  6.         WindowToken token = mTokenMap.get(attrs.token);  
  7.         ......  
  8.         win = new WindowState(this, session, client, token,  
  9.                 attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);  
  10.   
  11.         mWindowMap.put(client.asBinder(), win);  
  12.         ......  
  13. }  
根据Binder机制可以知道从上层应用传递过来的Token代理对象会转换成SystemServer进程中的Token本地对象,后者与第2步中从Token对象 是同一个对象,所以上面调用 mTokenMap.get(attrs.token)时便能返回正确返回一个WindowToken(这个WindowToken其实是一个APPWindowToken),这样添加的窗口也就跟Activity关联上了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值