【问题描述】java
音乐组同事反馈了一个必现Native Crash问题,tombstone以下:android
pid: 5028, tid: 5028, name: com.miui.player >>> com.miui.player <<< signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 79801f28 r0 7ac59c98 r1 00000000 r2 bea7b174 r3 400fc1b8 r4 774c4c88 r5 79801f28 r6 bea7b478 r7 40c12bb8 r8 7c1b68e8 r9 778781e8 sl bea7b478 fp bea7b414 ip 00000001 sp bea7b148 lr 40c07031 pc 79801f28 cpsr 600f0010 backtrace: #00 pc 0000bf28 <unknown> #01 pc 0002302f /system/lib/libhwui.so (android::uirenderer::OpenGLRenderer::callDrawGLFunction(android::Functor*, android::uirenderer::Rect&)+322) #02 pc 00015d91 /system/lib/libhwui.so (android::uirenderer::DrawFunctorOp::applyDraw(android::uirenderer::OpenGLRenderer&, android::uirenderer::Rect&)+28) #03 pc 00014527 /system/lib/libhwui.so (android::uirenderer::DrawBatch::replay(android::uirenderer::OpenGLRenderer&, android::uirenderer::Rect&, int)+74) #04 pc 00014413 /system/lib/libhwui.so (android::uirenderer::DeferredDisplayList::flush(android::uirenderer::OpenGLRenderer&, android::uirenderer::Rect&)+218) #05 pc 0001d1cf /system/lib/libhwui.so (_ZN7android10uirenderer14OpenGLRenderer15drawDisplayListEPNS0_11DisplayListERNS0_4RectEi.part.47+230) #06 pc 0006820d /system/lib/libandroid_runtime.so
崩溃的缘由是pc指向了一个没有可执行权限的内存地址上。c++
【问题分析】web
对应的代码以下:app
status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; detachFunctor(functor); ... interrupt(); // call functor immediately after GL state setup status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
其中,Functor类重载了()操做符:函数
class Functor { public: Functor() {} virtual ~Functor() {} virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; } };
所以,()操做其实就是调用了Functor类的一个虚函数,它的具体实现目前还不清楚。工具
对应的汇编代码以下:oop
23028: aa0b add r2, sp, #44 2302a: 6803 ldr r3, [r0, #0] ; r0是functor,r3 = [r0] = functor.vtlb 2302c: 689d ldr r5, [r3, #8] ; r5 = [r3 + 8] = [functor.vtlb + 8] = Functor.operator() 2302e: 47a8 blx r5 ; call Functor.operator()
崩溃时的寄存器值以下:ui
r0 7ac59c98 r1 00000000 r2 bea7b174 r3 400fc1b8 r4 774c4c88 r5 79801f28 r6 bea7b478 r7 40c12bb8 r8 7c1b68e8 r9 778781e8 sl bea7b478 fp bea7b414 ip 00000001 sp bea7b148 lr 40c07031 pc 79801f28 cpsr 600f0010
能够看到r5和pc值是相等的,确实是崩溃在2302e这一行汇编代码中。spa
而查看寄存器对应的内存值,发现有点问题:
memory near r0: 7ac59c78 00000018 0000001b 735a9b38 23831ef0 7ac59c88 23831ef0 735a9b50 00000018 00000011 7ac59c98 79822328 77768698 00000010 00000022 7ac59ca8 00000000 00000000 00000000 00000003 memory near r3: 400fc198 7c74c000 00200000 00000077 0d44acd8 400fc1a8 00000000 00000000 400fc1a8 400fc1a8 400fc1b8 400fc1b0 400fc1b0 7c04acb8 7c78f008 400fc1c8 7c021d98 7c78ffc0 7983bbf0 7c04bfa8
崩溃前:
2302a: 6803 ldr r3, [r0, #0]
但崩溃后tombstone打印内存值时,发现[r0] = 0x79822328,这与r3值0x400fc1b8不相同!
[r3+8] = [400fc1b8 + 8] = 7c04acb8,这个值也和r5值(79801f28)不同。
这在平时的tombstone里是很是少见的!
乍一看很是难以想象,但仔细想一想tombstone的生成过程,就能发现其中的问题。
原来寄存器信息是错位崩溃时的cpu context,保存在崩溃时的线程私有的信号栈和内核栈中,直到debuggerd去获取这个值,它是不会被修改。
而内存是进程中的各个线程共享的,因此在发生异常到debuggerd打印内存信息这段过程当中(实际上是相对很长的一个过程),别的线程是有可能修改内存值的。
为了证实别的线程在改这个内存值,在callDrawGLFunction()函数中的若干处打印了Functor和它的vtbl值:
status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { AOGI("functor=%p,vtbl=%p"); sleep(1); if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; AOGI("functor=%p,vtbl=%p"); sleep(1); detachFunctor(functor); ... AOGI("functor=%p,vtbl=%p"); sleep(1); interrupt(); AOGI("functor=%p,vtbl=%p"); sleep(1); // call functor immediately after GL state setup status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
抓到的log以下:
10-27 21:19:45.794 8027 8027 I OpenGLRenderer: functor=0x7a7b8530,vtbl=0x73648de0
10-27 21:19:47.801 8027 8027 I OpenGLRenderer: functor=0x7a7b8530,vtbl=0x73648de0
10-27 21:19:48.801 8027 8027 I OpenGLRenderer: functor=0x7a7b8530,vtbl=0x73648de0
10-27 21:19:49.801 8027 8027 I OpenGLRenderer: functor=0x7a7b8530,vtbl=0x73648de0
10-27 21:19:50.804 8027 8027 I OpenGLRenderer: functor=0x7a7b8530,vtbl=0x73648de0
10-27 21:19:51.804 8027 8027 I OpenGLRenderer: functor=0x7a7b8530,vtbl=0x400fc1b8
能够肯定确实有别的线程在修改这个值。
这里就存在两个可能性了:
一、别的线程也持有functor指针,并修改内容
二、functor是野指针,对应的内存已经还回系统,其余模块可任意使用。
而对象的vtbl通常是不会修改的,因此2的可能性更大一些。
为了查明是哪一个线程在改,对functor指向的内存作了写保护操做:
static int** s_saved_vtbl = NULL; static void* s_saved_functor = NULL; static void mprotect_local(int** p) { // 一旦发现vtbl有变化就将对应内存设置为只读 if(p != s_saved_vtbl) { mprotect((void*)((unsigned int)s_saved_functor&0xfffff000), 4096, PROT_READ); } sleep(1); } status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { int* ptr = (int*)functor; s_saved_functor = (void*)ptr; s_saved_vtbl = (int**)*ptr; if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; mprotect_local((int**)*ptr); detachFunctor(functor); mprotect_local((int**)*ptr); ... mprotect_local((int**)*ptr); interrupt(); // call functor immediately after GL state setup status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
push到手机中复现问题,很容易抓到crash,
而每次的crash的线程和位置都不同,也就是不一样的线程在不一样的函数中读写这个地址。
这样基本上就肯定是野指针问题,进入下一阶段的分析。
被析构的对象是Functor类的对象,
因为它的vtbl地址咱们可以从log中获取到,而vtbl通常指向定义了该类的so中,
因此用vtbl值(0x73648de0)去map表中找,就能肯定是哪一个so了。
...
73635000-73646000 rw-p 00000000 00:00 0
73646000-73648000 r-xp 00000000 b3:18 1287 /system/lib/libwebviewchromium_plat_support.so
73648000-73649000 r--p 00001000 b3:18 1287 /system/lib/libwebviewchromium_plat_support.so
73649000-7364a000 rw-p 00002000 b3:18 1287 /system/lib/libwebviewchromium_plat_support.so
而须要注意的是,C++对象的释放是delete函数,libwebviewchromium_plat_support.so不会直接调用libc的free函数,而是调用libc++.so中的delete函数。
先确认libwebviewchromium_plat_support.so是否依赖了delete函数:
$ readelf -s libwebviewchromium_plat_support.so |grep UND 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize 2: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit 4: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0 5: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr1 6: 00000000 0 FUNC GLOBAL DEFAULT UND getrlimit 7: 00000000 0 FUNC GLOBAL DEFAULT UND setrlimit 8: 00000000 0 FUNC GLOBAL DEFAULT UND __errno 9: 00000000 0 FUNC GLOBAL DEFAULT UND strerror 10: 00000000 0 FUNC GLOBAL DEFAULT UND __android_log_print 11: 00000000 0 FUNC GLOBAL DEFAULT UND _Znwj 12: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdlPv 14: 00000000 0 FUNC GLOBAL DEFAULT UND __android_log_assert ... 51: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_llsr 52: 00000000 0 OBJECT GLOBAL DEFAULT UND __popcount_tab
其中_Znwj是new的符号,_ZdlPv是delete的符号。
接下来就用工具hook libwebviewchromium_plat_support.so的delete函数:
extern void _ZdlPv(void *); void inject__ZdlPv(void* ptr) { LOGD("delete %p",ptr); dumpNativeStack(); dumpJavaStack(); _ZdlPv(ptr); }
hook后复现问题,抓到的log以下:
10-27 21:19:52.961 8027 8027 D ObserverLayout: onStop: clz=com.miui.player.display.view.DisplayFragmentLayout{45665838 V.E..... ........ 0,0-1080,1920 #7f080039 app:id/content} 10-27 21:19:52.965 8027 8027 I MusicBaseFragment: onDestroyView the view is still attached, delay destroy 10-27 21:19:52.966 8027 8027 D INJECT : delete 0x7a7b8530 10-27 21:19:52.986 8027 8027 D INJECT : #00 pc 000015f6 /system/lib/libinject.so (inject__ZdlPv+21) 10-27 21:19:52.986 8027 8027 D INJECT : #01 pc 00001134 /system/lib/libwebviewchromium_plat_supp 10-27 21:19:52.986 8027 8027 D INJECT : #02 pc 00001088 /system/lib/libwebviewchromium_plat_supp 10-27 21:19:52.987 8027 8027 D INJECT : #03 pc 0001d30c /system/lib/libdvm.so (dvmPlatformInvoke+112) 10-27 21:19:52.987 8027 8027 D INJECT : #04 pc 0004d8da /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JV+397) 10-27 21:19:52.987 8027 8027 D INJECT : #05 pc 00026720 /system/lib/libdvm.so 10-27 21:19:52.987 8027 8027 D INJECT : #06 pc 0002d790 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76) 10-27 21:19:52.987 8027 8027 D INJECT : #07 pc 0002adf4 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JVa+184) 10-27 21:19:52.988 8027 8027 D INJECT : #08 pc 00060058 /system/lib/libdvm.so (dvmInvokeMethod(Object*, Method const*, +391) 10-27 21:19:52.988 8027 8027 D INJECT : #09 pc 00067ff6 /system/lib/libdvm.so 10-27 21:19:52.988 8027 8027 D INJECT : #10 pc 00026720 /system/lib/libdvm.so 10-27 21:19:52.988 8027 8027 D INJECT : #11 pc 0002d790 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76) 10-27 21:19:52.988 8027 8027 D INJECT : #12 pc 0002adf4 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JVa+184) 10-27 21:19:52.988 8027 8027 D INJECT : #13 pc 0005fd74 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, O+335) 10-27 21:19:52.988 8027 8027 D INJECT : #14 pc 000494c2 /system/lib/libdvm.so 10-27 21:19:52.989 8027 8027 D INJECT : at com.android.webview.chromium.DrawGLFunctor.nativeDestroyGLFunctor(Native Method) 10-27 21:19:52.989 8027 8027 D INJECT : at com.android.webview.chromium.DrawGLFunctor.access$000(DrawGLFunctor.java:31) 10-27 21:19:52.989 8027 8027 D INJECT : at com.android.webview.chromium.DrawGLFunctor$DestroyRunnable.run(DrawGLFunctor.java:91) 10-27 21:19:52.989 8027 8027 D INJECT : at com.android.org.chromium.content.common.CleanupReference.runCleanupTaskInternal(CleanupReference.java:159) 10-27 21:19:52.989 8027 8027 D INJECT : at com.android.org.chromium.content.common.CleanupReference.access$300(CleanupReference.java:32) 10-27 21:19:52.989 8027 8027 D INJECT : at com.android.org.chromium.content.common.CleanupReference$LazyHolder$1.handleMessage(CleanupReference.java:93) 10-27 21:19:52.990 8027 8027 D INJECT : at com.android.org.chromium.content.common.CleanupReference.handleOnUiThread(CleanupReference.java:147) 10-27 21:19:52.990 8027 8027 D INJECT : at com.android.org.chromium.content.common.CleanupReference.cleanupNow(CleanupReference.java:141) 10-27 21:19:52.990 8027 8027 D INJECT : at com.android.webview.chromium.DrawGLFunctor.destroy(DrawGLFunctor.java:46) 10-27 21:19:52.990 8027 8027 D INJECT : at com.android.webview.chromium.WebViewChromium.destroy(WebViewChromium.java:430) 10-27 21:19:52.990 8027 8027 D INJECT : at android.webkit.WebView.destroy(WebView.java:667) 10-27 21:19:52.990 8027 8027 D INJECT : at com.xiaomi.music.hybrid.HybridFragment.destroyHybridView(HybridFragment.java:64) 10-27 21:19:52.990 8027 8027 D INJECT : at com.xiaomi.music.hybrid.HybridFragment.onDestroyView(HybridFragment.java:115) 10-27 21:19:52.990 8027 8027 D INJECT : at com.miui.player.component.MusicBaseFragment.onDestroyView(MusicBaseFragment.java:216) 10-27 21:19:52.991 8027 8027 D INJECT : at android.app.Fragment.performDestroyView(Fragment.java:1898) 10-27 21:19:52.991 8027 8027 D INJECT : at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:954) 10-27 21:19:52.991 8027 8027 D INJECT : at android.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1167) 10-27 21:19:52.991 8027 8027 D INJECT : at android.app.BackStackRecord.popFromBackStack(BackStackRecord.java:715) 10-27 21:19:52.991 8027 8027 D INJECT : at android.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1544) 10-27 21:19:52.992 8027 8027 D INJECT : at android.app.FragmentManagerImpl$3.run(FragmentManager.java:502) 10-27 21:19:52.992 8027 8027 D INJECT : at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1449) 10-27 21:19:52.992 8027 8027 D INJECT : at android.app.FragmentManagerImpl$1.run(FragmentManager.java:443) 10-27 21:19:52.992 8027 8027 D INJECT : at android.os.Handler.handleCallback(Handler.java:733) 10-27 21:19:52.992 8027 8027 D INJECT : at android.os.Handler.dispatchMessage(Handler.java:95) 10-27 21:19:52.992 8027 8027 D INJECT : at android.os.Looper.loop(Looper.java:136) 10-27 21:19:52.993 8027 8027 D INJECT : at android.app.ActivityThread.main(ActivityThread.java:5016) 10-27 21:19:52.993 8027 8027 D INJECT : at java.lang.reflect.Method.invokeNative(Native Method) 10-27 21:19:52.993 8027 8027 D INJECT : at java.lang.reflect.Method.invoke(Method.java:515) 10-27 21:19:52.993 8027 8027 D INJECT : at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792) 10-27 21:19:52.993 8027 8027 D INJECT : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608) 10-27 21:19:52.993 8027 8027 D INJECT : at dalvik.system.NativeStart.main(Native Method) 10-27 21:19:53.020 8027 8027 I OpenGLRenderer: functor=0x7a7b8530,vtbl=0x400fc1b8
从log中能够看到,确实是在distroy view的时候释放了Functor,而随后再Renderer中又使用了这个Functor。
打印崩溃时的java调用栈以下:
10-27 21:19:53.274 8027 8027 I dalvikvm: "main" prio=5 tid=1 TIMED_WAIT 10-27 21:19:53.279 8027 8027 I dalvikvm: | group="main" sCount=0 dsCount=0 obj=0x41716ca8 self=0x415344f8 10-27 21:19:53.279 8027 8027 I dalvikvm: | sysTid=6895 nice=-6 sched=0/0 cgrp=apps handle=1074409812 10-27 21:19:53.280 8027 8027 I dalvikvm: | state=R schedstat=( 0 0 0 ) utm=184 stm=61 core=3 10-27 21:19:53.280 8027 8027 I dalvikvm: at android.view.GLES20Canvas.nDrawDisplayList(Native Method) 10-27 21:19:53.281 8027 8027 I dalvikvm: at android.view.GLES20Canvas.drawDisplayList(GLES20Canvas.java:420) 10-27 21:19:53.281 8027 8027 I dalvikvm: at android.view.HardwareRenderer$GlRenderer.drawDisplayList(HardwareRenderer.java:1709) 10-27 21:19:53.281 8027 8027 I dalvikvm: at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1525) 10-27 21:19:53.282 8027 8027 I dalvikvm: at android.view.ViewRootImpl.draw(ViewRootImpl.java:2475) 10-27 21:19:53.282 8027 8027 I dalvikvm: at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2347) 10-27 21:19:53.283 8027 8027 I dalvikvm: at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1977) 10-27 21:19:53.284 8027 8027 I dalvikvm: at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1094) 10-27 21:19:53.285 8027 8027 I dalvikvm: at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5703) 10-27 21:19:53.285 8027 8027 I dalvikvm: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:764) 10-27 21:19:53.286 8027 8027 I dalvikvm: at android.view.Choreographer.doCallbacks(Choreographer.java:577) 10-27 21:19:53.287 8027 8027 I dalvikvm: at android.view.Choreographer.doFrame(Choreographer.java:547) 10-27 21:19:53.288 8027 8027 I dalvikvm: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:750) 10-27 21:19:53.289 8027 8027 I dalvikvm: at android.os.Handler.handleCallback(Handler.java:733) 10-27 21:19:53.289 8027 8027 I dalvikvm: at android.os.Handler.dispatchMessage(Handler.java:95) 10-27 21:19:53.290 8027 8027 I dalvikvm: at android.os.Looper.loop(Looper.java:136) 10-27 21:19:53.291 8027 8027 I dalvikvm: at android.app.ActivityThread.main(ActivityThread.java:5016) 10-27 21:19:53.291 8027 8027 I dalvikvm: at java.lang.reflect.Method.invokeNative(Native Method) 10-27 21:19:53.292 8027 8027 I dalvikvm: at java.lang.reflect.Method.invoke(Method.java:515) 10-27 21:19:53.293 8027 8027 I dalvikvm: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792) 10-27 21:19:53.293 8027 8027 I dalvikvm: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608) 10-27 21:19:53.293 8027 8027 I dalvikvm: at dalvik.system.NativeStart.main(Native Method)
正常状况下,view在被destroy后不该该再被绘制,这种状况多是view在destroy前没有remove致使的。
又发现delete时的调用栈中有两行特别的:
10-27 21:19:52.990 8027 8027 D INJECT : at com.xiaomi.music.hybrid.HybridFragment.destroyHybridView(HybridFragment.java:64) 10-27 21:19:52.990 8027 8027 D INJECT : at com.xiaomi.music.hybrid.HybridFragment.onDestroyView(HybridFragment.java:115)
这个是应用的代码,这个问题只有在这个应用上出现过,因此极可能是应用的代码引发的,因此查了下opengrok中的代码,发现有两处实现:
@packages/apps/MiuiMusic/common/music_sdk/hybrid/src/com/xiaomi/music/hybrid/HybridFragment.java private void destroyHybridView() { for (HybridView view : mHybridViews) { if (view != null) { view.destroy(); } } mHybridViews.clear(); } @packages/apps/MiuiSdk/library/src/java/miui/hybrid/HybridFragment.java private void destroyHybridView() { for (HybridView view : mHybridViews) { if (view != null) { if (view.getParent() != null) { ((ViewGroup) view.getParent()).removeView(view); } view.destroy(); } } mHybridViews.clear(); }
跟应用的同事沟通后得知,音乐应用是用上面的代码,也就是没有removeView的代码。
【解决方案】
将上面代码中添加removeView的逻辑后再也不复现问题。
虽然问题获得解决,但还不清楚为何没有removeView会致使野指针。
为了找到根源仔细阅读了相关代码,发现代码中Render中有detachFunctor的代码:
class GLES20Canvas extends HardwareCanvas { ... public void detachFunctor(int functor) { nDetachFunctor(mRenderer, functor); }
在这个代码中设置断点,用studio获得以下调用栈:
java.lang.Thread.State: RUNNABLE
at android.view.GLES20Canvas.detachFunctor(GLES20Canvas.java:321)
at android.view.HardwareRenderer$GlRenderer.detachFunctor(HardwareRenderer.java:1791)
at android.view.ViewRootImpl.detachFunctor(ViewRootImpl.java:744)
at com.android.webview.chromium.DrawGLFunctor$DestroyRunnable.detachNativeFunctor(DrawGLFunctor.java:97)
at com.android.webview.chromium.DrawGLFunctor.detach(DrawGLFunctor.java:53)
at com.android.webview.chromium.WebViewChromium.onDetachedFromWindow(WebViewChromium.java:1718)
at android.webkit.WebView.onDetachedFromWindow(WebView.java:2108)
at android.view.View.dispatchDetachedFromWindow(View.java:12631)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2587)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:3845)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:3818)
at android.view.ViewGroup.removeView(ViewGroup.java:3750)
at com.xiaomi.music.hybrid.HybridFragment.destroyHybridView(HybridFragment.java:66)
at com.xiaomi.music.hybrid.HybridFragment.onDestroyView(HybridFragment.java:119)
at com.miui.player.component.MusicBaseFragment.onDestroyView(MusicBaseFragment.java:216)
at android.app.Fragment.performDestroyView(Fragment.java:1898)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:954)
at android.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1167)
at android.app.BackStackRecord.popFromBackStack(BackStackRecord.java:715)
at android.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1544)
at android.app.FragmentManagerImpl$3.run(FragmentManager.java:502)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1449)
at android.app.FragmentManagerImpl$1.run(FragmentManager.java:443)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5016)
at java.lang.reflect.Method.invokeNative(Method.java:-1)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
at dalvik.system.NativeStart.main(NativeStart.java:-1)
加了removeView后,会从Render中删除Functor,这样Render在绘制时,再也不调用这个Functor。
这个问题只会在KK上有,L之后对Render作的很大改动,即便不作removeView,也不会存在野指针问题。