این بخش ابزارهای مفید و دستورات مرتبط را برای اشکال زدایی، ردیابی، و پروفایل کدهای پلتفرم اندروید بومی در هنگام توسعه ویژگی های سطح پلت فرم خلاصه می کند.
توجه: صفحات این بخش و جاهای دیگر این سایت استفاده از adb
همراه با آرگومان setprop
برای اشکال زدایی برخی از جنبه های اندروید توصیه می کنند. در اندروید 7.x و پایینتر، نام داراییها دارای محدودیت طول 32 نویسه بودند. این بدان معنی است که برای ایجاد یک ویژگی wrap با نام برنامه، لازم است نام را کوتاه کنید تا مناسب باشد. در اندروید 8.0 و بالاتر، این محدودیت بسیار بیشتر است و نباید به کوتاهی نیاز داشته باشد.
این صفحه اصول اولیه مربوط به خرابی های تصادفی که در خروجی logcat یافت می شود را پوشش می دهد. سایر صفحات جزئیات بسیار بیشتری در مورد تشخیص خرابی های بومی ، کاوش در سرویس های سیستم با dumpsys
، مشاهده حافظه بومی ، شبکه و استفاده از RAM ، استفاده از AddressSanitizer برای شناسایی اشکالات حافظه در کد بومی، ارزیابی مشکلات عملکرد (شامل systrace ) و استفاده از اشکال زدا دارند.
هنگامی که یک فایل اجرایی پیوند شده به صورت پویا شروع می شود، چندین کنترل کننده سیگنال ثبت می شوند که در صورت خرابی، باعث می شود که یک خرابی اولیه در logcat و یک فایل سنگ قبر با جزئیات بیشتر در /data/tombstones/
نوشته شود. سنگ قبر یک فایل با داده های اضافی در مورد فرآیند خراب است. به طور خاص، شامل ردیابی پشتهای برای همه رشتهها در فرآیند خرابی (نه فقط رشتهای که سیگنال را گرفت)، یک نقشه حافظه کامل، و فهرستی از تمام توصیفگرهای فایل باز است.
قبل از اندروید 8.0، خرابی ها توسط دیمون های debuggerd
و debuggerd64
مدیریت می شد. در اندروید 8.0 و بالاتر، crash_dump32
و crash_dump64
در صورت نیاز ایجاد میشوند.
این امکان وجود دارد که دامپر تصادف فقط در صورتی متصل شود که هیچ چیز دیگری قبلاً متصل نشده باشد، به این معنی که استفاده از ابزارهایی مانند strace
یا lldb
از رخ دادن خرابیهای تصادف جلوگیری میکند.
خروجی نمونه (با حذف مهرهای زمانی و اطلاعات اضافی):
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: 'Android/aosp_angler/angler:7.1.1/NYC/enh12211018:eng/test-keys' Revision: '0' ABI: 'arm' pid: 17946, tid: 17949, name: crasher >>> crasher <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc r0 0000000c r1 00000000 r2 00000000 r3 00000000 r4 00000000 r5 0000000c r6 eccdd920 r7 00000078 r8 0000461a r9 ffc78c19 sl ab209441 fp fffff924 ip ed01b834 sp eccdd800 lr ecfa9a1f pc ecfd693e cpsr 600e0030 backtrace: #00 pc 0004793e /system/lib/libc.so (pthread_mutex_lock+1) #01 pc 0001aa1b /system/lib/libc.so (readdir+10) #02 pc 00001b91 /system/xbin/crasher (readdir_null+20) #03 pc 0000184b /system/xbin/crasher (do_action+978) #04 pc 00001459 /system/xbin/crasher (thread_callback+24) #05 pc 00047317 /system/lib/libc.so (_ZL15__pthread_startPv+22) #06 pc 0001a7e5 /system/lib/libc.so (__start_thread+34) Tombstone written to: /data/tombstones/tombstone_06
آخرین خط خروجی محل سنگ قبر کامل روی دیسک را نشان می دهد.
اگر باینریهای جدا نشده را در دسترس دارید، میتوانید با چسباندن پشته در development/scripts/stack
جزئیات بیشتری را با اطلاعات شماره خط دریافت کنید:
development/scripts/stack
نکته: برای راحتی، اگر lunch
اجرا کرده اید، پس stack
از قبل روی $PATH
شما قرار دارد، بنابراین نیازی به ارائه مسیر کامل ندارید.
خروجی مثال (بر اساس خروجی logcat بالا):
Reading native crash info from stdin 03-02 23:53:49.477 17951 17951 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 03-02 23:53:49.477 17951 17951 F DEBUG : Build fingerprint: 'Android/aosp_angler/angler:7.1.1/NYC/enh12211018:eng/test-keys' 03-02 23:53:49.477 17951 17951 F DEBUG : Revision: '0' 03-02 23:53:49.477 17951 17951 F DEBUG : ABI: 'arm' 03-02 23:53:49.478 17951 17951 F DEBUG : pid: 17946, tid: 17949, name: crasher >>> crasher <<< 03-02 23:53:49.478 17951 17951 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc 03-02 23:53:49.478 17951 17951 F DEBUG : r0 0000000c r1 00000000 r2 00000000 r3 00000000 03-02 23:53:49.478 17951 17951 F DEBUG : r4 00000000 r5 0000000c r6 eccdd920 r7 00000078 03-02 23:53:49.478 17951 17951 F DEBUG : r8 0000461a r9 ffc78c19 sl ab209441 fp fffff924 03-02 23:53:49.478 17951 17951 F DEBUG : ip ed01b834 sp eccdd800 lr ecfa9a1f pc ecfd693e cpsr 600e0030 03-02 23:53:49.491 17951 17951 F DEBUG : 03-02 23:53:49.491 17951 17951 F DEBUG : backtrace: 03-02 23:53:49.492 17951 17951 F DEBUG : #00 pc 0004793e /system/lib/libc.so (pthread_mutex_lock+1) 03-02 23:53:49.492 17951 17951 F DEBUG : #01 pc 0001aa1b /system/lib/libc.so (readdir+10) 03-02 23:53:49.492 17951 17951 F DEBUG : #02 pc 00001b91 /system/xbin/crasher (readdir_null+20) 03-02 23:53:49.492 17951 17951 F DEBUG : #03 pc 0000184b /system/xbin/crasher (do_action+978) 03-02 23:53:49.492 17951 17951 F DEBUG : #04 pc 00001459 /system/xbin/crasher (thread_callback+24) 03-02 23:53:49.492 17951 17951 F DEBUG : #05 pc 00047317 /system/lib/libc.so (_ZL15__pthread_startPv+22) 03-02 23:53:49.492 17951 17951 F DEBUG : #06 pc 0001a7e5 /system/lib/libc.so (__start_thread+34) 03-02 23:53:49.492 17951 17951 F DEBUG : Tombstone written to: /data/tombstones/tombstone_06 Reading symbols from /huge-ssd/aosp-arm64/out/target/product/angler/symbols Revision: '0' pid: 17946, tid: 17949, name: crasher >>> crasher <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc r0 0000000c r1 00000000 r2 00000000 r3 00000000 r4 00000000 r5 0000000c r6 eccdd920 r7 00000078 r8 0000461a r9 ffc78c19 sl ab209441 fp fffff924 ip ed01b834 sp eccdd800 lr ecfa9a1f pc ecfd693e cpsr 600e0030 Using arm toolchain from: /huge-ssd/aosp-arm64/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/ Stack Trace: RELADDR FUNCTION FILE:LINE 0004793e pthread_mutex_lock+2 bionic/libc/bionic/pthread_mutex.cpp:515 v------> ScopedPthreadMutexLocker bionic/libc/private/ScopedPthreadMutexLocker.h:27 0001aa1b readdir+10 bionic/libc/bionic/dirent.cpp:120 00001b91 readdir_null+20 system/core/debuggerd/crasher.cpp:131 0000184b do_action+978 system/core/debuggerd/crasher.cpp:228 00001459 thread_callback+24 system/core/debuggerd/crasher.cpp:90 00047317 __pthread_start(void*)+22 bionic/libc/bionic/pthread_create.cpp:202 (discriminator 1) 0001a7e5 __start_thread+34 bionic/libc/bionic/clone.cpp:46 (discriminator 1)
شما می توانید stack
روی سنگ قبر کامل استفاده کنید. مثال:
stack < FS/data/tombstones/tombstone_05
اگر به تازگی یک گزارش اشکال را در فهرست فعلی از حالت فشرده خارج کرده باشید، مفید است. برای اطلاعات بیشتر در مورد تشخیص خرابیهای بومی و سنگ قبرها، به تشخیص خرابیهای بومی مراجعه کنید.
میتوانید از ابزار debuggerd
برای دریافت stack dump از یک فرآیند در حال اجرا استفاده کنید. از خط فرمان، debuggerd
با استفاده از شناسه فرآیند (PID) فراخوانی کنید تا سنگ قبر کامل را در stdout
قرار دهید. برای به دست آوردن فقط پشته برای هر رشته در فرآیند، پرچم -b
یا --backtrace
را اضافه کنید.
وقتی یک برنامه خراب می شود، پشته آن بسیار پیچیده است. مثال مفصل زیر بسیاری از پیچیدگی ها را برجسته می کند:
#00 pc 00000000007e6918 /system/priv-app/Velvet/Velvet.apk (offset 0x346b000) #01 pc 00000000001845cc /system/priv-app/Velvet/Velvet.apk (offset 0x346b000) #02 pc 00000000001847e4 /system/priv-app/Velvet/Velvet.apk (offset 0x346b000) #03 pc 00000000001805c0 /system/priv-app/Velvet/Velvet.apk (offset 0x346b000) (Java_com_google_speech_recognizer_AbstractRecognizer_nativeRun+176)
فریمهای #00–#03 از کدهای بومی JNI هستند که بهطور غیرفشرده در APK ذخیره میشوند تا فضای دیسک را ذخیره کنند تا اینکه در یک فایل .so
جداگانه استخراج شوند. Stack unwinder در اندروید 9 و بالاتر به فایل .so
استخراج شده برای مقابله با این مورد رایج مخصوص اندروید نیاز ندارد.
فریمهای #00–#02 نام نماد ندارند زیرا توسط توسعهدهنده حذف شدهاند.
فریم شماره 03 نشان می دهد که در جایی که نمادها در دسترس هستند، بازکننده از آنها استفاده می کند.
#04 pc 0000000000117550 /data/dalvik-cache/arm64/system@priv-app@Velvet@Velvet.apk@classes.dex (offset 0x108000) (com.google.speech.recognizer.AbstractRecognizer.nativeRun+160)
فریم شماره 04 کد جاوا زود کامپایل شده است. بازگشایی قدیمی در اینجا متوقف می شد و نمی توانست از طریق جاوا باز شود.
#05 pc 0000000000559f88 /system/lib64/libart.so (art_quick_invoke_stub+584) #06 pc 00000000000ced40 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200) #07 pc 0000000000280cf0 /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344) #08 pc 000000000027acac /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948) #09 pc 000000000052abc0 /system/lib64/libart.so (MterpInvokeDirect+296) #10 pc 000000000054c614 /system/lib64/libart.so (ExecuteMterpImpl+14484)
فریم های #05-#10 از پیاده سازی مفسر ART هستند. باز کردن پشته در نسخههای پایینتر از اندروید 9، این فریمها را بدون توضیح قاب شماره 11 نشان میداد که چه کدی را مفسر تفسیر میکند. اگر خود ART را اشکال زدایی می کنید، این فریم ها مفید هستند. اگر برنامه ای را اشکال زدایی می کنید، می توانید آنها را نادیده بگیرید. برخی از ابزارها، مانند simpleperf
، به طور خودکار این فریم ها را حذف می کنند.
#11 pc 00000000001992d6 /system/priv-app/Velvet/Velvet.apk (offset 0x26cf000) (com.google.speech.recognizer.AbstractRecognizer.run+18)
فریم شماره 11 کد جاوا در حال تفسیر است.
#12 pc 00000000002547a8 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496) #13 pc 000000000025a328 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216) #14 pc 000000000027ac90 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920) #15 pc 0000000000529880 /system/lib64/libart.so (MterpInvokeVirtual+584) #16 pc 000000000054c514 /system/lib64/libart.so (ExecuteMterpImpl+14228)
فریم های #12-#16 خود اجرای مفسر هستند.
#17 pc 00000000002454a0 /system/priv-app/Velvet/Velvet.apk (offset 0x1322000) (com.google.android.apps.gsa.speech.e.c.c.call+28)
فریم شماره 17 کد جاوا در حال تفسیر است. این روش جاوا با فریم های مفسر #12–#16 مطابقت دارد.
#18 pc 00000000002547a8 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496) #19 pc 0000000000519fd8 /system/lib64/libart.so (artQuickToInterpreterBridge+1032) #20 pc 00000000005630fc /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)
فریم های #18 تا #20 خود ماشین مجازی هستند، کدی برای انتقال از کد جاوا کامپایل شده به کد جاوا تفسیر شده.
#21 pc 00000000002ce44c /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.FutureTask.run+204)
فریم شماره 21 متد جاوا کامپایل شده است که متد جاوا را در شماره 17 فراخوانی می کند.
#22 pc 0000000000559f88 /system/lib64/libart.so (art_quick_invoke_stub+584) #23 pc 00000000000ced40 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200) #24 pc 0000000000280cf0 /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344) #25 pc 000000000027acac /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948) #26 pc 0000000000529880 /system/lib64/libart.so (MterpInvokeVirtual+584) #27 pc 000000000054c514 /system/lib64/libart.so (ExecuteMterpImpl+14228)
فریم های #22-#27 پیاده سازی مفسر هستند که یک متد را از کد تفسیر شده به یک متد کامپایل شده فراخوانی می کنند.
#28 pc 00000000003ed69e /system/priv-app/Velvet/Velvet.apk (com.google.android.apps.gsa.shared.util.concurrent.b.e.run+22)
فریم شماره 28 کد جاوا در حال تفسیر است.
#29 pc 00000000002547a8 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496) #30 pc 0000000000519fd8 /system/lib64/libart.so (artQuickToInterpreterBridge+1032) #31 pc 00000000005630fc /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)
فریم های #29-#31 انتقال دیگری بین کد کامپایل شده و کد تفسیر شده است.
#32 pc 0000000000329284 /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.ThreadPoolExecutor.runWorker+996) #33 pc 00000000003262a0 /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.ThreadPoolExecutor$Worker.run+64) #34 pc 00000000002037e8 /system/framework/arm64/boot.oat (offset 0xdc000) (java.lang.Thread.run+72)
فریم های #32–#34 فریم های جاوا کامپایل شده ای هستند که مستقیماً یکدیگر را فراخوانی می کنند. در این مورد پشته تماس بومی با پشته تماس جاوا یکسان است.
#35 pc 0000000000559f88 /system/lib64/libart.so (art_quick_invoke_stub+584) #36 pc 00000000000ced40 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200) #37 pc 0000000000280cf0 /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344) #38 pc 000000000027acac /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948) #39 pc 0000000000529f10 /system/lib64/libart.so (MterpInvokeSuper+1408) #40 pc 000000000054c594 /system/lib64/libart.so (ExecuteMterpImpl+14356)
فریم های #35-#40 خود مفسر هستند.
#41 pc 00000000003ed8e0 /system/priv-app/Velvet/Velvet.apk (com.google.android.apps.gsa.shared.util.concurrent.b.i.run+20)
فریم شماره 41 کد جاوا در حال تفسیر است.
#42 pc 00000000002547a8 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496) #43 pc 0000000000519fd8 /system/lib64/libart.so (artQuickToInterpreterBridge+1032) #44 pc 00000000005630fc /system/lib64/libart.so (art_quick_to_interpreter_bridge+92) #45 pc 0000000000559f88 /system/lib64/libart.so (art_quick_invoke_stub+584) #46 pc 00000000000ced40 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200) #47 pc 0000000000460d18 /system/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) #48 pc 0000000000461de0 /system/lib64/libart.so (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue*)+424) #49 pc 000000000048ccb0 /system/lib64/libart.so (art::Thread::CreateCallback(void*)+1120)
فریم های #42-#49 خود ماشین مجازی هستند. این بار این کد است که شروع به اجرای جاوا در یک رشته جدید می کند.
#50 pc 0000000000082e24 /system/lib64/libc.so (__pthread_start(void*)+36) #51 pc 00000000000233bc /system/lib64/libc.so (__start_thread+68)
فریم های #50-#51 نحوه شروع همه رشته ها هستند. این کد شروع رشته جدید libc
است.