ส่วนนี้จะสรุปเครื่องมือที่มีประโยชน์และคำสั่งที่เกี่ยวข้องสำหรับการดีบักการติดตามและการสร้างโปรไฟล์โค้ดแพลตฟอร์ม Android ดั้งเดิมเมื่อพัฒนาคุณลักษณะระดับแพลตฟอร์ม
หมายเหตุ: หน้าในส่วนนี้และส่วนอื่น ๆ ภายในไซต์นี้แนะนำให้ใช้ adb
ร่วมกับอาร์กิวเมนต์ setprop
เพื่อแก้ไขข้อบกพร่องบางประการของ Android ใน Android 7.x และต่ำกว่าชื่อคุณสมบัติมีความยาวไม่เกิน 32 อักขระ ซึ่งหมายความว่าในการสร้างคุณสมบัติการห่อด้วยชื่อของแอปนั้นจำเป็นต้องตัดชื่อให้พอดี ใน Android 8.0 ขึ้นไปขีด จำกัด นี้จะใหญ่กว่ามากและไม่ควรต้องมีการตัดทอน
หน้านี้ครอบคลุมพื้นฐานเกี่ยวกับการทิ้งข้อขัดข้องที่พบในเอาต์พุต logcat หน้าอื่น ๆ มีรายละเอียดเพิ่มเติมเกี่ยวกับ การวินิจฉัยข้อขัดข้อง ในระบบการสำรวจบริการระบบด้วยการ dumpsys
การดู หน่วยความจำดั้งเดิม เครือข่าย และการใช้ RAM โดยใช้ AddressSanitizer เพื่อตรวจจับข้อบกพร่องของหน่วยความจำในโค้ดเนทีฟการประเมิน ปัญหาด้านประสิทธิภาพ (รวมถึง systrace ) และการใช้ ดีบั๊ก
ทิ้งขยะและหลุมฝังศพ
เมื่อไฟล์ปฏิบัติการที่เชื่อมโยงแบบไดนามิกเริ่มทำงานตัวจัดการสัญญาณหลายตัวจะได้รับการลงทะเบียนซึ่งในกรณีที่เกิดข้อขัดข้องทำให้ดัมพ์ความผิดพลาดพื้นฐานถูกเขียนไปยัง logcat และไฟล์ tombstone ที่มี รายละเอียดเพิ่มเติมจะถูกเขียนไปยัง /data/tombstones/
หลุมฝังศพเป็นไฟล์ที่มีข้อมูลเพิ่มเติมเกี่ยวกับกระบวนการที่ขัดข้อง โดยเฉพาะอย่างยิ่งมีสแต็กเทรซสำหรับเธรดทั้งหมดในกระบวนการหยุดทำงาน (ไม่ใช่เฉพาะเธรดที่จับสัญญาณ) แมปหน่วยความจำแบบเต็มและรายการตัวอธิบายไฟล์ที่เปิดทั้งหมด
ก่อน Android 8.0 ข้อขัดข้องถูกจัดการโดย debuggerd
และ debuggerd64
daemons ใน Android 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
เพื่อรับสแต็กดัมพ์จากกระบวนการที่กำลังทำงานอยู่ จากบรรทัดคำสั่งเรียกใช้ debuggerd
โดยใช้ process ID (PID) เพื่อดัมพ์ tombstone แบบเต็มไปยัง stdout
หากต้องการรับเฉพาะสแต็กสำหรับทุกเธรดในกระบวนการให้รวมแฟ --backtrace
-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
เครื่องคลายสแต็กใน Android 9 ขึ้นไปไม่จำเป็นต้องใช้ไฟล์. .so
แยกออกมาเพื่อรับมือกับกรณีเฉพาะของ Android ทั่วไปนี้
เฟรม # 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)
Frame # 04 คือโค้ด Java ที่คอมไพล์ล่วงหน้า เครื่องคลายเก่าจะหยุดที่นี่ไม่สามารถคลายผ่าน Java ได้
#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 ตัวคลายสแต็กในรุ่นที่ต่ำกว่า Android 9 จะแสดงเฟรมเหล่านี้โดยไม่มีบริบทของเฟรม # 11 ที่อธิบายว่าล่ามแปลรหัสอะไร เฟรมเหล่านี้มีประโยชน์หากคุณกำลังแก้ไขข้อบกพร่องของ ART เอง หากคุณกำลังแก้ไขข้อบกพร่องของแอปคุณสามารถเพิกเฉยต่อแอปได้ เครื่องมือบางอย่างเช่น simpleperf
จะละเว้นเฟรมเหล่านี้โดยอัตโนมัติ
#11 pc 00000000001992d6 /system/priv-app/Velvet/Velvet.apk (offset 0x26cf000) (com.google.speech.recognizer.AbstractRecognizer.run+18)
Frame # 11 คือโค้ด Java ที่กำลังตีความ
#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)
Frame # 17 คือโค้ด Java ที่กำลังตีความ วิธีการ Java นี้สอดคล้องกับเฟรมตัวแปล # 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 คือตัว VM ซึ่งเป็นโค้ดสำหรับเปลี่ยนจากโค้ด Java ที่คอมไพล์แล้วเป็นโค้ด Java ที่ตีความ
#21 pc 00000000002ce44c /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.FutureTask.run+204)
Frame # 21 เป็นวิธี Java ที่คอมไพล์แล้วซึ่งเรียกใช้เมธอด Java ใน # 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)
Frame # 28 คือโค้ด Java ที่กำลังตีความ
#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 ถูกคอมไพล์เฟรม Java ที่เรียกหากันโดยตรง ในกรณีนี้สแต็กการโทรแบบเนทีฟจะเหมือนกับสแต็กการเรียก Java
#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)
Frame # 41 คือโค้ด Java ที่กำลังตีความ
#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 คือ VM นั้นเอง คราวนี้เป็นโค้ดที่เริ่มรัน Java บนเธรดใหม่
#50 pc 0000000000082e24 /system/lib64/libc.so (__pthread_start(void*)+36) #51 pc 00000000000233bc /system/lib64/libc.so (__start_thread+68)
เฟรม # 50– # 51 คือการเริ่มต้นของเธรดทั้งหมด นี่คือรหัสเริ่มต้นเธรดใหม่ของ libc