美文网首页Android开发经验谈Android技术知识程序员
Android:一个弹Toast导致系统崩溃问题分析

Android:一个弹Toast导致系统崩溃问题分析

作者: 我在等你回复可你没回 | 来源:发表于2019-06-06 17:06 被阅读9次
    我日

    现象:点击弹出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<int>(width),
                static_cast<int>(height), format, static_cast<int>(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

    好了,结束!!!!

    总结

    折腾了很久找必现路径和屏幕密度设置的地方。后续一些变量设置可以往应用端看或者服务端更上层的地方看,不用一层层地找。
    还有个问题,系统怎么没有对传入的参数进行验证呢??都传了这么大的值了。

    相关文章

      网友评论

        本文标题:Android:一个弹Toast导致系统崩溃问题分析

        本文链接:https://www.haomeiwen.com/subject/lwluxctx.html