android 弹出框崩溃_Android:一个弹Toast导致系统崩溃问题分析

我日

现象:点击弹出Toast,然后系统就崩溃了。我晕😵

一.首先查看崩溃信息,在mainlog或者/data/tombstones中找到。

05-31 08:32:26.710 1672 2342 F libc : Fatal signal 6 (SIGABRT), code -6 in tid 2342 (Binder:1672_3)

05-31 08:32:26.712 1590 1590 W : debuggerd: handling request: pid=1672 uid=1000 gid=1003 tid=2342

05-31 08:32:26.732 1696 2063 D audio_hal: out_get_latency: out(0xb6032000) latency=20

05-31 08:32:26.752 1696 2063 D audio_hal: out_get_latency: out(0xb6032000) latency=20

05-31 08:32:26.773 24584 24584 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

05-31 08:32:26.773 24584 24584 F DEBUG : Build fingerprint: 'HiSTBAndroidV6/Hi3798MV200/Hi3798MV200:7.0/NRD90M/lwf05300944:userdebug/test-keys'

05-31 08:32:26.773 24584 24584 F DEBUG : Revision: '0'

05-31 08:32:26.773 24584 24584 F DEBUG : ABI: 'arm'

05-31 08:32:26.773 24584 24584 F DEBUG : pid: 1672, tid: 2342, name: Binder:1672_3 >>> /system/bin/surfaceflinger <<<

05-31 08:32:26.773 24584 24584 F DEBUG : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------

05-31 08:32:26.773 24584 24584 F DEBUG : r0 00000000 r1 00000926 r2 00000006 r3 00000008

05-31 08:32:26.773 24584 24584 F DEBUG : r4 b2ab0978 r5 00000006 r6 b2ab0920 r7 0000010c

05-31 08:32:26.774 24584 24584 F DEBUG : r8 00000000 r9 00000000 sl 00000001 fp 00000000

05-31 08:32:26.774 24584 24584 F DEBUG : ip 00000016 sp b2ab0558 lr b6b6e397 pc b6b70bf4 cpsr 200d0010

05-31 08:32:26.788 24584 24584 F DEBUG :

05-31 08:32:26.788 24584 24584 F DEBUG : backtrace:

05-31 08:32:26.788 24584 24584 F DEBUG : #00 pc 00049bf4 /system/lib/libc.so (tgkill+12)

05-31 08:32:26.788 24584 24584 F DEBUG : #01 pc 00047393 /system/lib/libc.so (pthread_kill+34)

05-31 08:32:26.789 24584 24584 F DEBUG : #02 pc 0001d725 /system/lib/libc.so (raise+10)

05-31 08:32:26.789 24584 24584 F DEBUG : #03 pc 00019271 /system/lib/libc.so (__libc_android_abort+34)

05-31 08:32:26.789 24584 24584 F DEBUG : #04 pc 00017014 /system/lib/libc.so (abort+4)

05-31 08:32:26.789 24584 24584 F DEBUG : #05 pc 00006eb7 /system/lib/libui.so (_ZN7android22GraphicBufferAllocator5allocEjjijPPK13native_handlePj+390)

05-31 08:32:26.789 24584 24584 F DEBUG : #06 pc 00005f7b /system/lib/libui.so (_ZN7android13GraphicBuffer8initSizeEjjij+54)

05-31 08:32:26.789 24584 24584 F DEBUG : #07 pc 00005f23 /system/lib/libui.so (_ZN7android13GraphicBufferC2Ejjij+162)

05-31 08:32:26.789 24584 24584 F DEBUG : #08 pc 000407c9 /system/lib/libgui.so (_ZN7android18GraphicBufferAlloc19createGraphicBufferEjjijPi+36)

05-31 08:32:26.789 24584 24584 F DEBUG : #09 pc 0003b85d /system/lib/libgui.so (_ZN7android19BufferQueueProducer15allocateBuffersEjjij+244)

05-31 08:32:26.789 24584 24584 F DEBUG : #10 pc 00042149 /system/lib/libgui.so (_ZN7android23BnGraphicBufferProducer10onTransactEjRKNS_6ParcelEPS1_j+1312)

05-31 08:32:26.789 24584 24584 F DEBUG : #11 pc 000359b3 /system/lib/libbinder.so (_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j+70)

05-31 08:32:26.789 24584 24584 F DEBUG : #12 pc 0003d159 /system/lib/libbinder.so (_ZN7android14IPCThreadState14executeCommandEi+684)

05-31 08:32:26.789 24584 24584 F DEBUG : #13 pc 0003cdb7 /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+114)

05-31 08:32:26.789 24584 24584 F DEBUG : #14 pc 0003d2bb /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+46)

05-31 08:32:26.789 24584 24584 F DEBUG : #15 pc 0004f495 /system/lib/libbinder.so

05-31 08:32:26.789 24584 24584 F DEBUG : #16 pc 0000e361 /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+140)

05-31 08:32:26.789 24584 24584 F DEBUG : #17 pc 00046e63 /system/lib/libc.so (_ZL15__pthread_startPv+22)

05-31 08:32:26.789 24584 24584 F DEBUG : #18 pc 00019cbd /system/lib/libc.so (__start_thread+6)

大致可以看到是分配内存的时候崩了。通过ndk-stack工具查看堆栈:

pid: 1672, tid: 5522, name: Binder:1672_5 >>> /system/bin/surfaceflinger <<<

signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------

Stack frame #00 pc 00049bf4 /system/lib/libc.so (tgkill+12): Routine tgkill at /proc/self/cwd/bionic/libc/arch-arm/syscalls/tgkill.S:10

Stack frame #01 pc 00047393 /system/lib/libc.so (pthread_kill+34): Routine pthread_kill at /proc/self/cwd/bionic/libc/bionic/pthread_kill.cpp:45 (discriminator 4)

Stack frame #02 pc 0001d725 /system/lib/libc.so (raise+10): Routine raise at /proc/self/cwd/bionic/libc/bionic/raise.cpp:34 (discriminator 2)

Stack frame #03 pc 00019271 /system/lib/libc.so (__libc_android_abort+34): Routine __libc_android_abort at /proc/self/cwd/bionic/libc/bionic/abort.cpp:47

Stack frame #04 pc 00017014 /system/lib/libc.so (abort+4): Routine abort at /proc/self/cwd/bionic/libc/arch-arm/bionic/abort_arm.S:43

Stack frame #05 pc 00006ee9 /system/lib/libui.so (_ZN7android22GraphicBufferAllocator5allocEjjijPPK13native_handlePj+440): Routine android::Mutex::lock() at /proc/self/cwd/system/core/include/utils/Mutex.h:127 (discriminator 1)

Stack frame #06 pc 00005f7b /system/lib/libui.so (_ZN7android13GraphicBuffer8initSizeEjjij+54): Routine android::GraphicBuffer::initSize(unsigned int, unsigned int, int, unsigned int) at /proc/self/cwd/frameworks/native/libs/ui/GraphicBuffer.cpp:182 (discriminator 1)

Stack frame #07 pc 00005f23 /system/lib/libui.so (_ZN7android13GraphicBufferC2Ejjij+162): Routine GraphicBuffer at /proc/self/cwd/frameworks/native/libs/ui/GraphicBuffer.cpp:69

Stack frame #08 pc 000407c9 /system/lib/libgui.so (_ZN7android18GraphicBufferAlloc19createGraphicBufferEjjijPi+36): Routine ~BnInterface at /proc/self/cwd/frameworks/native/include/binder/IInterface.h:50

Stack frame #09 pc 0003b85d /system/lib/libgui.so (_ZN7android19BufferQueueProducer15allocateBuffersEjjij+244): Routine atrace_get_enabled_tags() at /proc/self/cwd/system/core/include/cutils/trace.h:156

Stack frame #10 pc 00042149 /system/lib/libgui.so (_ZN7android23BnGraphicBufferProducer10onTransactEjRKNS_6ParcelEPS1_j+1312): Routine android::BnGraphicBufferProducer::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int) at /proc/self/cwd/frameworks/native/libs/gui/IGraphicBufferProducer.cpp:581

可以看到的确是在分配内存的时候崩溃了。因此我们打印下参数。

status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,

PixelFormat format, uint32_t usage, buffer_handle_t* handle,

uint32_t* stride)

{

......................

ALOGD(" before GraphicBufferAllocator::alloc,alloc(%u, %u, %d, %08x, ...)",width, height, format, usage);

err = mAllocDev->alloc(mAllocDev, static_cast(width),

static_cast(height), format, static_cast(usage), handle,

&outStride);

......................

结果打印如下

image.png

可以看到长宽传入了1920*8947850。这么大,所以崩了。

二.回溯服务端的代码

SurfaceFinger的trace就是下面这些,对着上面ndk-stack的结果就行。

GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,PixelFormat inFormat, uint32_t inUsage)

GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage)

GraphicBufferAlloc::createGraphicBuffer(uint32_t width,uint32_t height, PixelFormat format, uint32_t usage, status_t* error)

BufferQueueProducer::dequeueBuffer

然后这个设置来源于一个binder通信,客户端的trace如下

Surface::allocateBuffers

void Surface::allocateBuffers() {

uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;

uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;

mGraphicBufferProducer->allocateBuffers(reqWidth, reqHeight,

mReqFormat, mReqUsage);

}

可以看到是来源于mReqWidth或者mUserWidth,但最后发现正常情况下这两个值都是0。说明不是这里设置的大小。

其实是在函数BufferQueueProducer::dequeueBuffer过程中,设置了默认的值。用这个默认的值来设置尺寸的。

const bool useDefaultSize = !width && !height;

if (useDefaultSize) {

width = mCore->mDefaultWidth;

height = mCore->mDefaultHeight;

}

所以我们要看这个mCore->mDefaultWidth和mCore->mDefaultHeight是从哪里来的。继续追溯一下

BufferQueueConsumer::setDefaultBufferSize

GLConsumer::setDefaultBufferSize

Layer::setBuffers

SurfaceFlinger::createNormalLayer

看到了把,是在创建一个Layer的时候就设置了大小的。是应用向SurfaceFinger发起申请,然后由SurfaceFlinger来创建这个Layer。应用端过程如下

SurfaceComposerClient::createSurface

android_view_SurfaceControl nativeCreate

所以是应用端在创建SurfaceControl的时候传入了大小。

好了,我们c的代码回溯完了,要继续往java层的回溯。

/frameworks/base/core/java/android/view/SurfaceControl 构造方法

/frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController 构造方法

/frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java

createSurfaceLocked

mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);

calculateSurfaceBounds(w, attrs);

final int width = mTmpSize.width();

final int height = mTmpSize.height();

可以长宽来自于一个mTmpSize的变量。

这个跟WindowState的mFrame变量相关,这个应该就是window的尺寸啦

这个计算在WindowState的computeFrameLw函数和applyGravityAndUpdateFrame函数中

看关键点。

image.png

是来源于mRequestedWidth,mRequestedHeight变量。

这两个变量是在WindowState的setRequestedSize方法设置的,这个方法在wms的relayoutWindow方法调用的,如下图

image.png

这个relayoutWindow大家很熟悉了,肯定是从应用端binder通信过来的。所以应用端传过来就传错了。打log看看如下

image.png

看到了把,很大很大。所以有问题。

三.追溯客户端的代码

在ViewRootImpl中设置尺寸。

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,

boolean insetsPending) throws RemoteException {

...........

..........

int relayoutResult = mWindowSession.relayout(

mWindow, mSeq, params,

(int) (mView.getMeasuredWidth() * appScale + 0.5f),

(int) (mView.getMeasuredHeight() * appScale + 0.5f),

viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,

mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,

mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,

mSurface);

............

打log可以发现是mView.getMeasuredWidth()和mView.getMeasuredHeight()过大,这个是获取view自身的大小的方法,大家都知道。

mView自然就是Toast的view啦。

所以我们要看下Toast是如何测量大小的。

四.确认Toast测量大小的方法

如下,可以看到Toast的高度mY是从一个Resource拿到的。

public Toast(Context context) {

mContext = context;

mTN = new TN();

mTN.mY = context.getResources().getDimensionPixelSize(

com.android.internal.R.dimen.toast_y_offset);

mTN.mGravity = context.getResources().getInteger(

com.android.internal.R.integer.config_toastDefaultGravity);

Log.e(TAG, "Toast construction mX= " + mTN.mX + " mY=" + mTN.mY + " mGravity=" + mTN.mGravity + " com.android.internal.R.dimen.toast_y_offset=" + com.android.internal.R.dimen.toast_y_offset);

}

image.png

是64dip,但最后发现这个mY超大。所以我们要看下getDimensionPixelSize的实现,这个方法其实就是通过dip计算返回像素值。

image.png

可以看到这个方法计算跟屏幕的密度有关系,最后打log发现出问题是屏幕的密度是Infinite,就是无限大。我天。

image.png

屏幕密度怎么会无限大呢?我百思不得其解。我在框架所有设置屏幕密度density的地方打log,没有发现被设置成无限大。糟糕。

image.png

难不成是应用设置的,应用还能设置屏幕密度???你别说,还真能!!

最后折腾了很久,发现是一个三方jar包搞的鬼,他设置了Activty的屏幕密度为无限大,导致了崩溃

image.png

好了,结束!!!!

总结

折腾了很久找必现路径和屏幕密度设置的地方。后续一些变量设置可以往应用端看或者服务端更上层的地方看,不用一层层地找。

还有个问题,系统怎么没有对传入的参数进行验证呢??都传了这么大的值了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值