Android 11 --关于Toast的异常
1.Android 11 -- 强制清理app后台,关于权限引发的问题2.Android 11 (MTK)状态栏图标反色-->跟随当前应用变化代码流程
3.Android 11 --关于Toast的异常
4.Android 11 -- 关于dialog和悬浮窗导致SystemUI状态栏下拉频繁闪烁(窗口焦点问题)5.Android 11 下拉菜单长按WiFi图标SystemUI ANR6.Android 11 sim卡来电不弹出悬浮通知,默认来电默认全屏7.Android Bluetooth 蓝牙开发/蓝牙协议 小结8.Android11 —— 自定义添加一个System Services9.Android系统——AOSP相关-->随记10.Android11 , Launcher3 切换阿拉伯语,最近应用(后台)不能滑动11.Android 底层问题日志记录12.Android 11 -- app 服务保活13.Android11 - 添加自定义服务注意事项14.Android 11 导航栏添加一个虚拟按钮--问题合集15.Android 11--设置第三方Launcher并默认 与 如何预置apk16.Android11 系统修改 AOSP输入法的默认输入键盘布局17.Settings里面切换不同Launcher的代码流程18.关于Android`系统默认屏保`19.关于Android 11 Settings添加新的选项界面的细节20.Android 11 自由窗口模式 || 全屏模式启动app21.强制app横屏显示或者竖屏显示(动态)22.Android 11 禁止从SD卡上安装第三方应用23.实体物理音量键替换为home键24.AMS- kill Launcher进程的代码流程25.Android 11 recovery恢复出厂设置保留某些文件26.Android 11 禁用 adb root (userdebug版本)27.Android11 应用默认获取通知使用权限(可以获取系统所有通知信息)28.Android 11 UsbDebug 关于adb RSA 认证29.Android 11 NavigationBar && Status Bar 如果改变背景颜色30.Anroid 11 关于NotificationManager && NotificationManagerService -- 衍生到权限管理31.Android13 控制设置界面 双栏显示或单栏显示32.Android 13 大屏显示时关于SystemUI和Launcher3问题33.Android 系统适配无源码app34.Android 11 关于app的权限重置35.Android 11.0 关于app进程保活36.Android 11 关于按键拦截/按键事件处理分享37.Android R Settings关于屏保/PowerManagerService欺骗系统不让其进入休眠状态38.Android13 关于SystemUI更新/Nav Bar add volume button&&other button39.Android 13 移植EthernetSettings/Ethernet更新40.Anrdoir 13 关于设置静态IP后,突然断电,在上电开机卡动画41.Android T(13) The app is granted permissions by default42.Android T 关于屏幕旋转 (一)43.Android T about screen rotation(二)44.Android 13 about launcher3 (1)45.Android T don't abort background activity starts46.Android T adout replace bootanimation47.Launcher start App WINDOWING_MODE_FREEFORM48.Android 11 About SleepToken / (Settings)Screen timeout49.Settings.System数据监听/prop&SystemProperties数据监听WMS 服务关于Toast异常
Window和View的关系:
Window 是View的载体。每个view树都可以看成一个window。
view树中的每个view显示次序是固定,activity里面设置一个布局xml文件,最顶层的布局就是view树的根节点。
一个自定义布局的Dialog,Dialog的顶层布局就不属于activity的View树,这是2个View树,所以是2个Window。
Window 的一些重要属性:
Window的 type 属性决定了window的显示次序,大致分为1-1000 为低层,1001-2000为中层,2000以上为高层。
应用程序窗口:应用程序窗口一般位于最底层,z-order在1-99
子窗口:子窗口一般是显示在应用窗口之上,z-order在1000-1999
系统级窗口:系统级窗口一般位于最顶层,不会被其他的window遮住,如Toast,z-order在2000-2999
z-order越大,window显示越高,高度高的window会覆盖高度低的window,跟搭积木一样。
Window的flag属性 flag标志控制window的显示,Window的softInputMode属性,当软键盘弹出是,对当前window的控制。
Android 11 分屏(不同的displayId) 显示 Toast造成的SystemUI的ANR
bug报错日志:
11-09 11:26:15.814 9306 9306 W ToastUI : Attempt to hide non-current toast from package com.acloud.stub.localmusic
11-09 11:26:15.823 1392 5481 W WindowManager: Attempted to add window to a display for which the application does not have access: 0. Aborting.
11-09 11:26:15.824 9306 9306 D AndroidRuntime: Shutting down VM
11-09 11:26:15.825 9306 9306 E AndroidRuntime: FATAL EXCEPTION: main
11-09 11:26:15.825 9306 9306 E AndroidRuntime: Process: com.android.systemui, PID: 9306
11-09 11:26:15.825 9306 9306 E AndroidRuntime: android.view.WindowManager$InvalidDisplayException: Unable to add window android.view.ViewRootImpl$W@6061d4d -- the specified display can not be found
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at android.view.ViewRootImpl.setView(ViewRootImpl.java:1101)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:409)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:110)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at android.widget.ToastPresenter.show(ToastPresenter.java:210)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at com.android.systemui.toast.ToastUI.showToast(ToastUI.java:96)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at com.android.systemui.statusbar.CommandQueue$H.handleMessage(CommandQueue.java:1285)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at android.os.Looper.loop(Looper.java:223)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7705)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
11-09 11:26:15.825 9306 9306 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:952)
根据日志跟踪代码进行分析:
当时看到这个报错日志也是有点看不明白,不明白为什么Toast的显示,和system UI有什么关系。
但是报错全是标记到这里了,那就跟踪代码!
com.android.systemui.toast.ToastUI
@Override
@MainThread
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
.........
mPresenter = new ToastPresenter(context, mAccessibilityManager, mNotificationManager,
packageName);
mPresenter.show(view, token, windowToken, duration, mGravity, 0, mY, 0, 0, mCallback);
}
@Override
@MainThread
public void hideToast(String packageName, IBinder token) {
if (mPresenter == null || !Objects.equals(mPresenter.getPackageName(), packageName)
|| !Objects.equals(mPresenter.getToken(), token)) {
Log.w(TAG, "Attempt to hide non-current toast from package " + packageName);
return;
}
hideCurrentToast();
}
//systemUI中的toastUI 又重新new了一个ToastPresenter来用于toast的显示
ToastPresenter.java
public void show(View view, IBinder token, IBinder windowToken, int duration, int gravity,
int xOffset, int yOffset, float horizontalMargin, float verticalMargin,
@Nullable ITransientNotificationCallback callback) {
............
if (mView.getParent() != null) {
mWindowManager.removeView(mView);
}
try {
mWindowManager.addView(mView, mParams);
} catch (WindowManager.BadTokenException e) {
// Since the notification manager service cancels the token right after it notifies us
// to cancel the toast there is an inherent race and we may attempt to add a window
// after the token has been invalidated. Let us hedge against that.
Log.w(TAG, "Error while attempting to show toast from " + mPackageName, e);
return;
}
................
}
//ToastPresenter 是通过 mWindowManager.addView(mView, mParams); 将toast 显示,这个具体实现实在WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
int requestUserId) {
................
synchronized (mGlobalLock) {
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
if (displayContent == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window to a display that does "
+ "not exist: %d. Aborting.", displayId);
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
//关键代码
if (!displayContent.hasAccess(session.mUid)) {
ProtoLog.w(WM_ERROR,
"Attempted to add window to a display for which the application "
+ "does not have access: %d. Aborting.", displayId);
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
//报错日志发源地....
if (mWindowMap.containsKey(client.asBinder())) {
ProtoLog.w(WM_ERROR, "Window %s is already added", client);
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
.................
}
跳转到DisplayContent.java
/**
* Returns true if the specified UID has access to this display.
* 如果指定的UID可以访问此显示,返回true,而bug中的toast不是默认的display显示,
* 而是在另外的display,所以返回false, !false == true,就报错 return WindowManagerGlobal.ADD_INVALID_DISPLAY
*/
boolean hasAccess(int uid) {
return mDisplay.hasAccess(uid);
}
最后代码执行到ViewRootImpl.java中的setView(xxx)
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
.......
int res; /* = WindowManagerImpl.ADD_OKAY; */
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
mAdded = false;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
switch (res) {
..................
case WindowManagerGlobal.ADD_INVALID_DISPLAY:
throw new WindowManager.InvalidDisplayException("Unable to add window "
+ mWindow + " -- the specified display can not be found");
..................
}
throw new RuntimeException(
"Unable to add window -- unknown error code " + res);
}
..........
}
看完整个代码流程,有两个方法可以尝试:
方法一:
在ToastPresenter.java 中的show()方法去再次try catch WindowManager.InvalidDisplayException 整个异常,
这样systemUI不会崩溃,但是分屏中的应用的toast不显示
try {
...............
} catch (WindowManager.BadTokenException e) {
............
Log.w(TAG, "Error while attempting to show toast from " + mPackageName, e);
return;
}catch (WindowManager.InvalidDisplayException e){
Log.w(TAG, "InvalidDisplayException->Error while attempting to show toast from" + mPackageName, e);
return;
}
方法二:
DisplayContent.java 中的hasAccess()方法,多添加一个判断,让它在mDisplayId不同的时候返回true
boolean hasAccess(int uid) {
//add
if(!isDefaultDisplay){
return diffDisplay();
}
//end
return mDisplay.hasAccess(uid);
}
private boolean diffDisplay() {
if (mDisplayId != DEFAULT_DISPLAY) {
return true;
}
return false;
}
分类:
Android
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库