android token机制_Android之window机制token验证

本文深入探讨了 Android 中的 Token 机制,特别是在显示 Dialog 时使用 Activity 和 Application Context 的区别。Token 在 Android 系统中扮演着验证角色,确保只有拥有合法 Token 的 Activity 才能进行 UI 操作。通过源码分析,揭示了 Token 的创建、传递和验证过程,以及它如何限制不同类型 Context 的权限。文章强调了理解 Token 机制对于正确使用 Android 组件的重要性,并提倡遵循设计原则,避免滥用 Context。
摘要由CSDN通过智能技术生成

前言

很高兴遇见你~ 欢迎阅读我的文章

这篇文章讲解关于window token的问题,同时也是Context机制和Window机制这两篇文章的一个补充。如果你对Android的Window机制和Context机制目前位了解过,强烈建议你先阅读前面两篇文章,可以帮助理解整个源码的解析过程以及对token的理解。同时文章涉及到Activty启动流程源码,读者可先阅读Activity启动流程这篇文章。文章涉及到这些方面的内容默认读者已经阅读且了解,不会对这方面的内容过多阐述,如果遇到一些内容不理解,可以找到对应的文章看一下。那么,我们开始吧。

当我们想要在屏幕上展示一个Dialog的时候,我们可能会在Activity的onCreate方法里这么写:

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

val dialog = AlertDialog.Builder(this)

dialog.run{

title = "我是标题"

setMessage("我是内容")

}

dialog.show()

}

他的构造参数需要一个context对象,但是这个context不能是ApplicationContext等其他context,只能是ActivityContext(当然没有ApplicationContext这个类,也没有ActivityContext这个类,这里这样写只是为了方便区分context类型,下同)。这样的代码运行时没问题的,如果我们使用Application传入会怎么样呢?

override fun onCreate(savedInstanceState: Bundle?) {

...

// 注意这里换成了ApplicationContext

val dialog = AlertDialog.Builder(applicationContext)

...

}

运行一下:

3d401bbc0ebf506e094e68d9e78f57c6.png

报错了,原因是You need to use a Theme.AppCompat theme (or descendant) with this activity.,那我们给他添加一个Theme:

override fun onCreate(savedInstanceState: Bundle?) {

...

// 注意这里添加了主题

val dialog = AlertDialog.Builder(applicationContext,R.style.AppTheme)

...

}

好了再次运行:

d50ccdcc18c7cc65eb7700a543023ddf.png

嗯嗯?又崩溃了,原因是:Unable to add window -- token null is not valid; is your activity running?token为null?这个token是什么?为什么同样是context,使用activity没问题,用ApplicationContext就出问题了?他们之间有什么区别?那么这篇文章就围绕这个token来展开讨论一下。

文章采用思考问题的思路来展开讲述,我会根据我学习这部分内容时候的思考历程进行复盘。希望这种解决问题的思维可以帮助到你。

对token有一定了解的读者可以看到最后部分的整体流程把握,再选择想阅读的部分仔细阅读。

什么是token

首先我们看到报错是在ViewRootImpl.java:907,这个地方肯定有进行token判断,然后抛出异常,这样我们就能找到token了,那我们直接去这个地方看看。:

ViewRootImpl.class(api29)

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

...

int res;

...

res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,

getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,

mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,

mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,

mTempInsets);

...

if (res < WindowManagerGlobal.ADD_OKAY) {

...

switch (res) {

case WindowManagerGlobal.ADD_BAD_APP_TOKEN:

case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:

/*

*1

*/

throw new WindowManager.BadTokenException(

"Unable to add window -- token " + attrs.token

+ " is not valid; is your activity running?");

...

}

...

}

...

}

我们看到代码就是在注释1的地方抛出了异常,是根据一个变量res来判断的,这个res来自方法addToDisplay,那么token的判断肯定在这个方法里面了,res只是一个 判断的结果,那么我们需要进到这个addToDisplay里去看一下。mWindowSession的类型是IWindowSession,他是一个接口,那他的实现类是什么?找不到实现类就无法知道他的具体代码。这里涉及到window机制的相关内容,简单讲一下:

WindowManagerService是系统服务进程,应用进程跟window联系需要通过跨进程通信:AIDL,这里的IWindowSession只是一个Binder接口,他的具体实现类在系统服务进程的Session类。所以这里的逻辑就跳转到了Session类的addToDisplay方法中。关于window机制更加详细的内容,读者可以阅读Android全面解析之Window机制这篇文章进一步了解,限于篇幅这里不过多讲解。

那我们继续到Session的方法中看一下:

Session.class(api29)

class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {

final WindowManagerService mService;

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,

int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,

Rect outStableInsets, Rect outOutsets,

DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,

InsetsState outInsetsState) {

return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,

outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,

outInsetsState);

}

}

可以看到,Session确实是继承自接口IWindowSession,因为WMS和Session都是运行在系统进程,所以不需要跨进程通信,直接调用WMS的方法:

public int addWindow(Session session, IWindow client, int seq,

LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,

Rect outContentInsets, Rect outStableInsets, Rect outOutsets,

DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,

InsetsState outInsetsState) {

...

WindowState parentWindow = null;

...

// 获取parentWindow

parentWindow = windowForClientLocked(null, attrs.token, false);

...

final boolean hasParent = parentWindow != null;

// 获取token

WindowToken token = displayContent.getWindowToken(

hasParent ? parentWindow.mAttrs.token : attrs.token);

...

// 验证token

if (token == null) {

if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {

Slog.w(TAG_WM, "Attempted to add

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值