ส่วนนี้จะสรุปเครื่องมือที่มีประโยชน์และคำสั่งที่เกี่ยวข้องสำหรับการแก้ไขข้อบกพร่อง การติดตาม และการสร้างโปรไฟล์โค้ดแพลตฟอร์ม 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
ใน 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
โดยใช้รหัสกระบวนการ (PID) เพื่อถ่ายโอนข้อมูลแผ่นป้ายหลุมศพแบบสมบูรณ์ไปยัง stdout
หากต้องการดูเฉพาะสแต็กของทุกชุดข้อความในกระบวนการ ให้ใส่ Flag -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)
เฟรม #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)
เฟรม #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)
เฟรม #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)
เฟรม #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)
เฟรม #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)
เฟรม #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
รหัสเริ่มต้นชุดข้อความใหม่