Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
Android ƽ̨ Native ´úÂëµÄ±ÀÀ£²¶»ñ»úÖÆ¼°ÊµÏÖ
 
À´Ô´£ºÀ´×ÔÍøÂç ·¢²¼ÓÚ2017-7-17
  2447  次浏览      29
 

Ò»¡¢±³¾°

ÔÚAndroidƽ̨£¬native crashÒ»Ö±ÊÇcrashÀïµÄ´óÍ·¡£native crash¾ßÓÐÉÏÏÂÎIJ»È«¡¢³ö´íÐÅϢģºý¡¢ÄÑÒÔ²¶×½µÈÌØµã£¬±Èjava crash¸üÄÑÐÞ¸´¡£ËùÒÔÒ»¸öºÏ¸ñµÄÒì³£²¶»ñ×é¼þÒ²ÒªÄÜ´ïµ½ÒÔÏÂÄ¿µÄ£º

Ö§³ÖÔÚcrashʱ½øÐиü¶àÀ©Õ¹²Ù×÷£¬È磺

1.´òÓ¡logcatºÍÓ¦ÓÃÈÕÖ¾

2.Éϱ¨crash´ÎÊý

3.¶Ô²»Í¬µÄcrash×ö²»Í¬µÄ»Ö¸´´ëÊ©

4.¿ÉÒÔÕë¶ÔÒµÎñ²»¶Ï¸Ä½øºÍÊÊÓ¦

¶þ¡¢ÏÖÓеķ½°¸

Æäʵ3¸ö·½°¸ÔÚAndroidƽ̨µÄʵÏÖÔ­Àí¶¼ÊÇ»ù±¾Ò»Öµģ¬×ۺϿ¼ÂÇ£¬¿ÉÒÔ»ùÓÚcoffeecatch¸Ä½ø¡£

Èý¡¢ÐźŻúÖÆ

1.³ÌÐò±¼À£

ÔÚUnix-likeϵͳÖУ¬ËùÓеıÀÀ£¶¼ÊDZà³Ì´íÎó»òÕßÓ²¼þ´íÎóÏà¹ØµÄ£¬ÏµÍ³Óöµ½²»¿É»Ö¸´µÄ´íÎóʱ»á´¥·¢±ÀÀ£»úÖÆÈóÌÐòÍ˳ö£¬Èç³ýÁã¡¢¶ÎµØÖ·´íÎóµÈ¡£

Òì³£·¢Éúʱ£¬CPUͨ¹ýÒì³£Öжϵķ½Ê½£¬´¥·¢Òì³£´¦ÀíÁ÷³Ì¡£²»Í¬µÄ´¦ÀíÆ÷£¬Óв»Í¬µÄÒì³£ÖжÏÀàÐͺÍÖжϴ¦Àí·½Ê½¡£

linux°ÑÕâЩÖжϴ¦Àí£¬Í³Ò»ÎªÐźÅÁ¿£¬¿ÉÒÔ×¢²áÐźÅÁ¿ÏòÁ¿½øÐд¦Àí¡£

ÐźŻúÖÆÊǽø³ÌÖ®¼äÏ໥´«µÝÏûÏ¢µÄÒ»ÖÖ·½·¨£¬ÐźÅÈ«³ÆÎªÈíÖжÏÐźš£

2.ÐźŻúÖÆ

º¯ÊýÔËÐÐÔÚÓû§Ì¬£¬µ±Óöµ½ÏµÍ³µ÷Óá¢ÖжϻòÊÇÒì³£µÄÇé¿öʱ£¬³ÌÐò»á½øÈëÄÚºË̬¡£ÐźÅÉæ¼°µ½ÁËÕâÁ½ÖÖ״̬֮¼äµÄת»»¡£

(1) ÐźŵĽÓÊÕ

½ÓÊÕÐźŵÄÈÎÎñÊÇÓÉÄں˴úÀíµÄ£¬µ±Äں˽ÓÊÕµ½Ðźź󣬻ὫÆä·Åµ½¶ÔÓ¦½ø³ÌµÄÐźŶÓÁÐÖУ¬Í¬Ê±Ïò½ø³Ì·¢ËÍÒ»¸öÖжϣ¬Ê¹ÆäÏÝÈëÄÚºË̬¡£×¢Ò⣬´ËʱÐźŻ¹Ö»ÊÇÔÚ¶ÓÁÐÖУ¬¶Ô½ø³ÌÀ´ËµÔÝʱÊDz»ÖªµÀÓÐÐźŵ½À´µÄ¡£

(2) Ðźŵļì²â

½ø³ÌÏÝÈëÄÚºË̬ºó£¬ÓÐÁ½ÖÖ³¡¾°»á¶ÔÐźŽøÐмì²â£º

½ø³Ì´ÓÄÚºË̬·µ»Øµ½Óû§Ì¬Ç°½øÐÐÐźżì²â

½ø³ÌÔÚÄÚºË̬ÖУ¬´Ó˯Ãß״̬±»»½ÐѵÄʱºò½øÐÐÐźżì²â

µ±·¢ÏÖÓÐÐÂÐźÅʱ£¬±ã»á½øÈëÏÂÒ»²½£¬ÐźŵĴ¦Àí¡£

(3) ÐźŵĴ¦Àí

ÐźŴ¦Àíº¯ÊýÊÇÔËÐÐÔÚÓû§Ì¬µÄ£¬µ÷Óô¦Àíº¯Êýǰ£¬Äں˻Ὣµ±Ç°ÄÚºËÕ»µÄÄÚÈݱ¸·Ý¿½±´µ½Óû§Õ»ÉÏ£¬²¢ÇÒÐÞ¸ÄÖ¸Áî¼Ä´æÆ÷£¨eip£©½«ÆäÖ¸ÏòÐźŴ¦Àíº¯Êý¡£

½ÓÏÂÀ´½ø³Ì·µ»Øµ½Óû§Ì¬ÖУ¬Ö´ÐÐÏàÓ¦µÄÐźŴ¦Àíº¯Êý¡£

ÐźŴ¦Àíº¯ÊýÖ´ÐÐÍê³Éºó£¬»¹ÐèÒª·µ»ØÄÚºË̬£¬¼ì²éÊÇ·ñ»¹ÓÐÆäËüÐźÅδ´¦Àí¡£Èç¹ûËùÓÐÐźŶ¼´¦ÀíÍê³É£¬¾Í»á½«ÄÚºËÕ»»Ö¸´£¨´ÓÓû§Õ»µÄ±¸·Ý¿½±´»ØÀ´£©£¬Í¬Ê±»Ö¸´Ö¸Áî¼Ä´æÆ÷£¨eip£©½«ÆäÖ¸ÏòÖжÏǰµÄÔËÐÐλÖã¬×îºó»Øµ½Óû§Ì¬¼ÌÐøÖ´Ðнø³Ì¡£

ÖÁ´Ë£¬Ò»¸öÍêÕûµÄÐźŴ¦ÀíÁ÷³Ì±ã½áÊøÁË£¬Èç¹ûͬʱÓжà¸öÐźŵ½´ï£¬ÉÏÃæµÄ´¦ÀíÁ÷³Ì»áÔÚµÚ2²½ºÍµÚ3²½Öè¼äÖØ¸´½øÐС£

(4) ³£¼ûÐźÅÁ¿ÀàÐÍ

ËÄ¡¢²¶×½native crash

1.×¢²áÐźŴ¦Àíº¯Êý

µÚÒ»²½¾ÍÊÇÒªÓÃÐźŴ¦Àíº¯Êý²¶»ñµ½native crash(SIGSEGV, SIGBUSµÈ)¡£ÔÚposixϵͳ£¬¿ÉÒÔÓÃsigaction()£º

#include <signal.h>
int sigaction(int signum,const struct

sigaction *act,struct sigaction *oldact));

1.signum£º´ú±íÐźűàÂ룬¿ÉÒÔÊdzýSIGKILL¼°SIGSTOPÍâµÄÈκÎÒ»¸öÌØ¶¨ÓÐЧµÄÐźţ¬Èç¹ûΪÕâÁ½¸öÐźŶ¨Òå×Ô¼ºµÄ´¦Àíº¯Êý£¬½«µ¼ÖÂÐźŰ²×°´íÎó¡£

2.act£ºÖ¸Ïò½á¹¹ÌåsigactionµÄÒ»¸öʵÀýµÄÖ¸Õ룬¸ÃʵÀýÖ¸¶¨Á˶ÔÌØ¶¨ÐźŵĴ¦Àí£¬Èç¹ûÉèÖÃΪ¿Õ£¬½ø³Ì»áÖ´ÐÐĬÈÏ´¦Àí¡£

3.oldact£ººÍ²ÎÊýactÀàËÆ£¬Ö»²»¹ý±£´æµÄÊÇÔ­À´¶ÔÏàÓ¦ÐźŵĴ¦Àí£¬Ò²¿ÉÉèÖÃΪNULL¡£

struct sigaction sa_old;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = my_handler;
sa.sa_flags = SA_SIGINFO;
if (sigaction(sig, &sa, &sa_old) == 0) {
...
}

2.ÉèÖöîÍâÕ»¿Õ¼ä

#include <signal.h>
int sigaltstack(const stack_t *ss,

stack_t *oss);

SIGSEGVºÜÓпÉÄÜÊÇÕ»Òç³öÒýÆðµÄ£¬Èç¹ûÔÚĬÈϵÄÕ»ÉÏÔËÐкÜÓпÉÄÜ»áÆÆ»µ³ÌÐòÔËÐеÄÏÖ³¡£¬ÎÞ·¨»ñÈ¡µ½ÕýÈ·µÄÉÏÏÂÎÄ¡£¶øÇÒµ±Õ»ÂúÁË£¨Ì«¶à´ÎµÝ¹é£¬Õ»ÉÏÌ«¶à¶ÔÏ󣩣¬ÏµÍ³»áÔÚͬһ¸öÒѾ­ÂúÁ˵ÄÕ»Éϵ÷ÓÃSIGSEGVµÄÐźŴ¦Àíº¯Êý£¬ÓÖÔÙÒ»´ÎÒýÆðͬÑùµÄÐźš£

ÎÒÃÇÓ¦¸Ã¿ª±ÙÒ»¿éеĿռä×÷ΪÔËÐÐÐźŴ¦Àíº¯ÊýµÄÕ»¡£¿ÉÒÔʹÓÃsigaltstackÔÚÈÎÒâÏß³Ì×¢²áÒ»¸ö¿ÉÑ¡µÄÕ»£¬±£ÁôÒ»ÏÂÔÚ½ô¼±Çé¿öÏÂʹÓõĿռ䡣£¨ÏµÍ³»áÔÚΣÏÕÇé¿öϰÑÕ»Ö¸ÕëÖ¸ÏòÕâ¸öµØ·½£¬Ê¹µÃ¿ÉÒÔÔÚÒ»¸öеÄÕ»ÉÏÔËÐÐÐźŴ¦Àíº¯Êý£©

stack_t stack;
memset(&stack, 0, sizeof(stack));
/* Reserver the system default stack size.

We don't need that much by the way. */
stack.ss_size = SIGSTKSZ;
stack.ss_sp = malloc(stack.ss_size);
stack.ss_flags = 0;
/* Install alternate stack size. Be sure

the memory region is valid until you revert it. */
if (stack.ss_sp != NULL && sigaltstack

(&stack, NULL) == 0) {
...
}

3.¼æÈÝÆäËûsignal´¦Àí

static void my_handler(const int code, siginfo_t

*const si, void *const sc) {
...
/* Call previous handler. */
old_handler.sa_sigaction(code, si, sc);
}

ijЩÐźſÉÄÜÔÚ֮ǰÒѾ­±»°²×°¹ýÐźŴ¦Àíº¯Êý£¬¶øsigactionÒ»¸öÐźÅÁ¿Ö»ÄÜ×¢²áÒ»¸ö´¦Àíº¯Êý£¬ÕâÒâζ×ÅÎÒÃǵĴ¦Àíº¯Êý»á¸²¸ÇÆäËûÈ˵Ĵ¦ÀíÐźÅ

±£´æ¾ÉµÄ´¦Àíº¯Êý£¬ÔÚ´¦ÀíÍêÎÒÃǵÄÐźŴ¦Àíº¯Êýºó£¬ÔÚÖØÐÂÔËÐÐÀϵĴ¦Àíº¯Êý¾ÍÄÜÍê³É¼æÈÝ¡£

Îå¡¢×¢ÒâÊÂÏî

1.·ÀÖ¹ËÀËø»òÕßËÀÑ­»·

Ê×ÏÈÎÒÃÇÒªÁ˽âasync-signal-safeºÍ¿ÉÖØÈ뺯Êý¸ÅÄ

»ØÏëÏÂÔÚ¡°ÐźŻúÖÆ¡±Ò»½ÚÖеÄͼʾ£¬½ø³Ì²¶×½µ½ÐźŲ¢¶ÔÆä½øÐд¦Àíʱ£¬½ø³ÌÕýÔÚÖ´ÐеÄÕý³£Ö¸ÁîÐòÁоͱ»ÐźŴ¦Àí³ÌÐòÁÙʱÖжϣ¬ËüÊ×ÏÈÖ´ÐиÃÐźŴ¦Àí³ÌÐòÖеÄÖ¸ÁÀàËÆ·¢ÉúÓ²¼þÖжϣ©¡£µ«ÔÚÐźŴ¦Àí³ÌÐòÖУ¬²»ÄÜÅжϲ¶×½µ½ÐźÅʱ½ø³ÌÖ´Ðе½ºÎ´¦¡£Èç¹û½ø³ÌÕýÔÚÖ´ÐÐmalloc£¬ÔÚÆä¶ÑÖзÖÅäÁíÍâµÄ´æ´¢¿Õ¼ä£¬¶ø´ËʱÓÉÓÚ²¶×½µ½ÐźŶø²åÈëÖ´ÐиÃÐźŴ¦Àí³ÌÐò£¬ÆäÖÐÓÖµ÷ÓÃmalloc£¬Õâʱ»á·¢Éúʲô£¿Õâ¿ÉÄÜ»á¶Ô½ø³ÌÔì³ÉÆÆ»µ£¬ÒòΪmallocͨ³£ÎªËüËù·ÖÅäµÄ´æ´¢ÇøÎ¬»¤Ò»¸öÁ´±í£¬¶ø²åÈëÖ´ÐÐÐźŴ¦Àí³ÌÐòʱ£¬½ø³Ì¿ÉÄÜÕýÔÚ¸ü¸Ä´ËÁ´±í¡££¨²Î¿¼¡¶UNIX»·¾³¸ß¼¶±à³Ì¡·£©

Single UNIX Specification˵Ã÷ÁËÔÚÐźŴ¦Àí³ÌÐòÖб£Ö¤µ÷Óð²È«µÄº¯Êý¡£ÕâЩº¯ÊýÊÇ¿ÉÖØÈëµÄ²¢±»³ÆÎªÊÇÒì²½ÐźŰ²È«£¨async-signal-safe£©¡£³ýÁË¿ÉÖØÈëÒÔÍ⣬ÔÚÐźŴ¦Àí²Ù×÷ÆÚ¼ä£¬Ëü»á×èÈûÈκλáÒýÆð²»Ò»ÖµÄÐźŷ¢ËÍ¡£ÏÂÃæÊÇÕâЩÒì²½ÐźŰ²È«º¯Êý£º

µ«¼´Ê¹ÎÒÃÇ×Ô¼ºÔÚÐźŴ¦Àí³ÌÐòÖв»Ê¹Óò»¿ÉÖØÈëµÄº¯Êý£¬Ò²ÎÞ·¨±£Ö¤±£´æµÄ¾ÉµÄÐźŴ¦Àí³ÌÐòÖв»»áÓзÇÒì²½ÐźŰ²È«µÄº¯Êý¡£ËùÒÔҪʹÓÃalarm±£Ö¤ÐźŴ¦Àí³ÌÐò²»»áÏÝÈëËÀËø»òÕßËÀÑ­»·µÄ״̬¡£

static void signal_handler(const int code, siginfo_t

*const si,
void *const sc) {

/* Ensure we do not deadlock. Default of

ALRM is to die.
* (signal() and alarm() are signal-safe) */
signal(code, SIG_DFL);
signal(SIGALRM, SIG_DFL);

/* Ensure we do not deadlock. Default of

ALRM is to die.
* (signal() and alarm() are signal-safe) */
(void) alarm(8);
....
}

2.ÔÚÄÄÀï´òÓ¡¶ÑÕ»

(1) ×Ó½ø³Ì

¿¼Âǵ½ÐźŴ¦Àí³ÌÐòÖеÄÖî¶àÏÞÖÆ£¬Ò»°ã»ácloneÒ»¸öеĽø³Ì£¬ÔÚÆäÖÐÍê³É½âÎö¶ÑÕ»µÈÈÎÎñ¡£

ÏÂÃæÊÇGoogle BreakpadµÄÁ÷³Ìͼ£¬ÔÚеĽø³ÌÖÐDoDump£¬Ê¹ÓÃptrace½âÎöcrash½ø³ÌµÄ¶ÑÕ»£¬Í¬Ê±ÐźŴ¦Àí³ÌÐòµÈ´ý×Ó½ø³ÌÍê³ÉÈÎÎñºó£¬ÔÙµ÷ÓþɵÄÐźŴ¦Àíº¯Êý¡£¸¸×Ó½ø³ÌʹÓùܵÀͨÐÅ¡£

(2) ×ÓÏß³Ì

ÔÚÎÒµÄʵÑéÖУ¬ÔÚ×Ó½ø³Ì»òÕßÐźŴ¦Àíº¯ÊýÖУ¬¾­³£ÎÞ·¨»Øµ÷¸øjava²ã¡£ÓÚÊÇÎÒÑ¡ÔñÁËÔÚ³õʼ»¯µÄʱºò¾Í½¨Á¢ÁË×ÓÏ̲߳¢Ò»Ö±µÈ´ý£¬µÈµ½²¶×½µ½crashÐźÅʱ£¬»½ÐÑÕâÌõÏß³Ìdump³öcrash¶ÑÕ»£¬²¢°Ñcrash¶ÑÕ»»Øµ÷¸øjava¡£

static void nativeInit(JNIEnv* env, jclass

javaClass, jstring packageNameStr, jstring

tombstoneFilePathStr, jobject obj) {
...
initCondition();

pthread_t thd;
int ret = pthread_create(&thd, NULL,

DumpThreadEntry, NULL); if(ret) {
qmlog("%s", "pthread_create error");
}
}

void* DumpThreadEntry(void *argv) {
JNIEnv* env = NULL;
if((*g_jvm)->AttachCurrentThread(g_jvm,

&env, NULL) != JNI_OK)
{
LOGE("AttachCurrentThread() failed");
estatus = 0;
return &estatus;
}

while (true) {
//µÈ´ýÐźŴ¦Àíº¯Êý»½ÐÑ
waitForSignal();

//»Øµ÷nativeÒì³£¶ÑÕ»¸øjava²ã
throw_exception(env);

//¸æËßÐźŴ¦Àíº¯ÊýÒѾ­´¦ÀíÍêÁË
notifyThrowException();
}

if((*g_jvm)->DetachCurrentThread(g_jvm)

!= JNI_OK)
{
LOGE("DetachCurrentThread() failed");
estatus = 0;
return &estatus;
}

return &estatus;
}

Áù¡¢ÊÕ¼¯native crashÔ­Òò

ÐźŴ¦Àíº¯ÊýµÄÈë²ÎÖÐÓзḻµÄ´íÎóÐÅÏ¢£¬ÏÂÃæÎÒÃÇÀ´Ò»Ò»·ÖÎö¡£

/*ÐźŴ¦Àíº¯Êý*/

void (*sa_sigaction)(const int code,

siginfo_t *const si, void * const sc)

siginfo_t {
int si_signo; /* Signal number ÐźÅÁ¿ */
int si_errno; /* An errno value */
int si_code; /* Signal code ´íÎóÂë */
}

1.code

·¢Éúnative crashÖ®ºó£¬logcatÖлá´ò³öÈçÏÂÒ»¾äÐÅÏ¢£º

signal 11 (SIGSEGV), code 0 (SI_USER), fault addr 0x0

¸ù¾ÝcodeÈ¥²é±í£¬Æäʵ¾Í¿ÉÒÔÖªµÀ·¢Éúnative crashµÄ´óÖÂÔ­Òò£º

´úÂëµÄÒ»²¿·ÖÈçÏ£¬Æäʵ¾ÍÊǸù¾Ý²»Í¬µÄcode£¬Êä³ö²»Í¬ÐÅÏ¢£¬ÕâЩ¶¼Êǹ̶¨µÄ¡£

case SIGFPE:
switch(code) {
case FPE_INTDIV:
return "Integer divide by zero";
case FPE_INTOVF:
return "Integer overflow";
case FPE_FLTDIV:
return "Floating-point divide by zero";
case FPE_FLTOVF:
return "Floating-point overflow";
case FPE_FLTUND:
return "Floating-point underflow";
case FPE_FLTRES:
return "Floating-point inexact result";
case FPE_FLTINV:
return "Invalid floating-point operation";
case FPE_FLTSUB:
return "Subscript out of range";
default:
return "Floating-point";
}
break;
case SIGSEGV:
switch(code) {
case SEGV_MAPERR:
return "Address not mapped to object";
case SEGV_ACCERR:
return "Invalid permissions for mapped object";
default:
return "Segmentation violation";
}
break;

2.pcÖµ

ÐźŴ¦Àíº¯ÊýÖеĵÚÈý¸öÈë²ÎscÊÇuc_mcontextµÄ½á¹¹Ì壬ÊÇcpuÏà¹ØµÄÉÏÏÂÎÄ£¬°üÀ¨µ±Ç°Ï̵߳ļĴæÆ÷ÐÅÏ¢ºÍ±¼À£Ê±µÄpcÖµ¡£Äܹ»ÖªµÀ±ÀÀ£Ê±µÄpc£¬¾ÍÄÜÖªµÀ±ÀÀ£Ê±Ö´ÐеÄÊÇÄÇÌõÖ¸Áî¡£

²»¹ýÕâ¸ö½á¹¹ÌåµÄ¶¨ÒåÊÇÆ½Ì¨Ïà¹Ø£¬²»Í¬Æ½Ì¨¡¢²»Í¬cpu¼Ü¹¹Öе͍Òå¶¼²»Ò»Ñù£º

1.x86-64¼Ü¹¹£ºuc_mcontext.gregs[REG_RIP]

2.arm¼Ü¹¹£ºuc_mcontext.arm_pc

3.¹²Ïí¿âÃû×ÖºÍÏà¶ÔÆ«ÒÆµØÖ·

(1) dladdr()

pcÖµÊdzÌÐò¼ÓÔØµ½ÄÚ´æÖеľø¶ÔµØÖ·£¬ÎÒÃÇÐèÒªÄõ½±¼À£´úÂëÏà¶ÔÓÚ¹²Ïí¿âµÄÏà¶ÔÆ«ÒÆµØÖ·£¬²ÅÄÜʹÓÃaddr2line·ÖÎö³öÊÇÄÄÒ»ÐдúÂ롣ͨ¹ýdladdr()¿ÉÒÔ»ñµÃ¹²Ïí¿â¼ÓÔØµ½ÄÚ´æµÄÆðʼµØÖ·£¬ºÍpcÖµÏà¼õ¾Í¿ÉÒÔ»ñµÃÏà¶ÔÆ«ÒÆµØÖ·£¬²¢ÇÒ¿ÉÒÔ»ñµÃ¹²Ïí¿âµÄÃû×Ö¡£

Dl_info info;
if (dladdr(addr, &info) != 0 && info.dli_

fname != NULL) {
void * const nearest = info.dli_saddr;
//Ïà¶ÔÆ«ÒÆµØÖ·
const uintptr_t addr_relative =
((uintptr_t) addr - (uintptr_t) info.dli_fbase);
...
}

×÷ΪÓÐ×·ÇóµÄÎÒÃÇ£¬¿Ï¶¨²»Âú×ãÓÚ½ö½öͨ¹ýÒ»¸öº¯Êý¾Í»ñµÃ´ð°¸¡£ÎÒÃdz¢ÊÔÏÂÈçºÎÊÖ¹¤·ÖÎö³öÏà¶ÔµØÖ·¡£Ê×ÏÈÒªÁ˽âϽø³ÌµÄµØÖ·¿Õ¼ä²¼¾Ö¡£

(2) LinuxϽø³ÌµÄµØÖ·¿Õ¼ä²¼¾Ö

ÈκÎÒ»¸ö³ÌÐòͨ³£¶¼°üÀ¨´úÂë¶ÎºÍÊý¾Ý¶Î£¬ÕâЩ´úÂëºÍÊý¾Ý±¾Éí¶¼ÊǾ²Ì¬µÄ¡£³ÌÐòÒªÏëÔËÐУ¬Ê×ÏÈÒªÓɲÙ×÷ϵͳ¸ºÔðΪÆä´´½¨½ø³Ì£¬²¢ÔÚ½ø³ÌµÄÐéÄâµØÖ·¿Õ¼äÖÐΪÆä´úÂë¶ÎºÍÊý¾Ý¶Î½¨Á¢Ó³Éä¡£¹âÓдúÂë¶ÎºÍÊý¾Ý¶ÎÊDz»¹»µÄ£¬½ø³ÌÔÚÔËÐйý³ÌÖл¹ÒªÓÐÆä¶¯Ì¬»·¾³£¬ÆäÖÐ×îÖØÒªµÄ¾ÍÊǶÑÕ»¡£

ÉÏͼÖÐRandom stack offsetºÍRandom mmap offsetµÈËæ»úÖµÒâÔÚ·ÀÖ¹¶ñÒâ³ÌÐò¡£Linuxͨ¹ý¶ÔÕ»¡¢ÄÚ´æÓ³Éä¶Î¡¢¶ÑµÄÆðʼµØÖ·¼ÓÉÏËæ»úÆ«ÒÆÁ¿À´´òÂÒ²¼¾Ö£¬ÒÔÃâ¶ñÒâ³ÌÐòͨ¹ý¼ÆËã·ÃÎÊÕ»¡¢¿âº¯ÊýµÈµØÖ·¡£

Õ»(stack)£¬×÷Ϊ½ø³ÌµÄÁÙʱÊý¾ÝÇø,Ôö³¤·½ÏòÊǴӸߵØÖ·µ½µÍµØÖ·¡£

(3) /proc/self/maps£º¼ì²é¸÷¸öÄ£¿é¼ÓÔØÔÚÄÚ´æµÄµØÖ··¶Î§

ÔÚLinuxϵͳÖУ¬/proc/self/maps±£´æÁ˸÷¸ö³ÌÐò¶ÎÔÚÄÚ´æÖеļÓÔØµØÖ··¶Î§£¬grep³ö¹²Ïí¿âµÄÃû×Ö£¬¾Í¿ÉÒÔÖªµÀ¹²Ïí¿âµÄ¼ÓÔØ»ùÖµÊǶàÉÙ¡£

µÃµ½Ïà¶ÔÆ«ÒÆµØÖ·Ö®ºó£¬Ê¹ÓÃreadelf²é¿´¹²Ïí¿âµÄ·ûºÅ±í£¬¾Í¿ÉÒÔÖªµÀÊÇÄĸöº¯ÊýcrashÁË¡£

Æß¡¢»ñÈ¡¶ÑÕ»

1.Ô­Àí

ÔÚǰһ²½£¬ÎÒÃÇ»ñÈ¡Á˱¼À£Ê±µÄpcÖµºÍ¸÷¸ö¼Ä´æÆ÷µÄÄÚÈÝ£¬Í¨¹ýSPºÍFPËùÏÞ¶¨µÄstack frame£¬¾Í¿ÉÒԵõ½Ä¸º¯ÊýµÄSPºÍFP£¬´Ó¶øµÃµ½Ä¸º¯ÊýµÄstack frame£¨PC£¬LR£¬SP£¬FP»áÔÚº¯Êýµ÷ÓõĵÚһʱ¼äѹջ£©£¬ÒÔ´Ë×·ËÝ£¬¼´¿ÉµÃµ½ËùÓк¯ÊýµÄµ÷ÓÃ˳Ðò¡£

2.ʵÏÖ

ÔÚ4.1.1ÒÔÉÏ£¬5.0ÒÔÏ£ºÊ¹Óð²×¿ÏµÍ³×Ô´øµÄlibcorkscrew.so

5.0ÒÔÉÏ£º°²×¿ÏµÍ³ÖÐûÓÐÁËlibcorkscrew.so£¬Ê¹ÓÃ×Ô¼º±àÒëµÄlibunwind

#ifdef USE_UNWIND
/* Frame buffer initial position. */
t->frames_size = 0;

/* Skip us and the caller. */
t->frames_skip = 0;

/* ʹÓÃlibcorkscrew½â¶ÑÕ» */
#ifdef USE_CORKSCREW
t->frames_size = backtrace_signal(si, sc,

t->frames, 0, BACKTRACE_FRAMES_MAX);
#else
/* Unwind frames (equivalent to backtrace()) */
_Unwind_Backtrace(coffeecatch_unwind_callback, t);
#endif

/* Èç¹ûÎÞ·¨¼ÓÔØlibcorkscrew£¬ÔòʹÓÃ×Ô¼º±àÒëµÄ

libunwind½â¶ÑÕ» */

#ifdef USE_LIBUNWIND
if (t->frames_size == 0) {
size_t i;
t->frames_size = unwind_signal(si, sc,

t->uframes, 0,BACKTRACE_FRAMES_MAX);
for(i = 0 ; i < t->frames_size ; i++) {
t->frames[i].absolute_pc = (uintptr_t)

t->uframes[i];
t->frames[i].stack_top = 0;
t->frames[i].stack_size = 0;
__android_log_print(ANDROID_LOG_DEBUG, TAG, "absolute_pc:%x", t->frames[i].absolute_pc);
}
}
#endif

libunwindÊÇÒ»¸ö¶ÀÁ¢µÄ¿ªÔ´¿â£¬¸ß°æ±¾µÄ°²×¿Ô´ÂëÖÐҲʹÓÃÁËlibunwind×÷Ϊ½â¶ÑÕ»µÄ¹¤¾ß£¬²¢Õë¶Ô°²×¿×öÁËһЩÊÊÅä¡£ÏÂÃæÊÇʹÓÃlibunwind½â¶ÑÕ»µÄÖ÷Ñ­»·£¬Ã¿´ÎÑ­»·½âÒ»²ã¶ÑÕ»¡£

static ALWAYS_INLINE int
slow_backtrace (void **buffer, int size,

unw_context_t *uc)
{
unw_cursor_t cursor;
unw_word_t ip;
int n = 0;

if (unlikely (unw_init_local (&cursor, uc) < 0))
return 0;

while (unw_step (&cursor) > 0)
{
if (n >= size)
return n;
if (unw_get_reg (&cursor, UNW_REG_IP, &ip) < 0)
return n;
buffer[n++] = (void *) (uintptr_t) ip;
}
return n;
}

°Ë¡¢»ñÈ¡º¯Êý·ûºÅ

(1) libcorkscrew

¿ÉÒÔͨ¹ýlibcorkscrewÖеÄget_backtrace_symbolsº¯Êý»ñµÃº¯Êý·ûºÅ¡£

/*
* Describes the symbols associated with a

backtrace frame.
*/
typedef struct {
uintptr_t relative_pc;
uintptr_t relative_symbol_addr;
char* map_name;
char* symbol_name;
char* demangled_name;
} backtrace_symbol_t;

/*
* Gets the symbols for each frame of a backtrace.
* The symbols array must be big enough to

hold one symbol record per frame.
* The symbols must later be freed using

free_backtrace_symbols.
*/

void get_backtrace_symbols(const

backtrace_frame_t* backtrace, size_t frames,
backtrace_symbol_t* backtrace_symbols);

(2) dladdr

¸üͨÓõķ½·¨ÊÇͨ¹ýdladdr»ñµÃº¯ÊýÃû×Ö¡£

int dladdr(void *addr, Dl_info *info);

typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Base address at which shared
object is loaded */
const char *dli_sname; /* Name of symbol whose definition
overlaps addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;

´«Èëÿһ²ã¶ÑÕ»µÄÏà¶ÔÆ«ÒÆµØÖ·£¬¾Í¿ÉÒÔ´Ódli_fnameÖлñµÃº¯ÊýÃû×Ö¡£

¾Å¡¢»ñµÃjava¶ÑÕ»

ÈçºÎ»ñµÃnative crashËù¶ÔÓ¦µÄjava²ã¶ÑÕ»£¬Õâ¸öÎÊÌâÔø¾­À§ÈÅÁËÎÒÒ»¶Îʱ¼ä¡£ÕâÀïÓÐÒ»¸öǰÌ᣺ÎÒÃÇÈÏΪcrashÏ߳̾ÍÊDz¶»ñµ½ÐźŵÄỊ̈߳¬ËäÈ»ÕâÔÚSIGABRTϲ»Ò»¶¨¿É¿¿¡£ÓÐÁËÕâ¸öÈÏÖª£¬½ÓÏÂÀ´¾ÍºÃ°ìÁË¡£ÔÚÐźŴ¦Àíº¯ÊýÖлñµÃµ±Ç°Ï̵߳ÄÃû×Ö£¬È»ºó°ÑcrashÏ̵߳ÄÃû×Ö´«¸øjava²ã£¬ÔÚjavaÀïdump³öÕâ¸öÏ̵߳ĶÑÕ»£¬¾ÍÊÇcrashËù¶ÔÓ¦µÄjava²ã¶ÑÕ»ÁË¡£

ÔÚcÖлñµÃÏß³ÌÃû×Ö£º

char* getThreadName(pid_t tid) {
if (tid <= 1) {
return NULL;
}
char* path = (char *) calloc(1, 80);
char* line = (char *) calloc(1, THREAD_NAME_LENGTH);

snprintf(path, PATH_MAX, "proc/%d/comm", tid);
FILE* commFile = NULL;
if (commFile = fopen(path, "r")) {
fgets(line, THREAD_NAME_LENGTH, commFile);
fclose(commFile);
}
free(path);
if (line) {
int length = strlen(line);
if (line[length - 1] == '\n') {
line[length - 1] = '\0';
}
}
return line;
}

È»ºó´«¸øjava²ã£º

/**
* ¸ù¾ÝÏß³ÌÃû»ñµÃÏ̶߳ÔÏó£¬native²ã»áµ÷Óø÷½·¨£¬

²»ÄÜ»ìÏý
* @param threadName
* @return
*/
@Keep
public static Thread getThreadByName(String

threadName) {
if (TextUtils.isEmpty(threadName)) {
return null;
}

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.

toArray(new Thread[threadSet.size()]);

Thread theThread = null;
for(Thread thread : threadArray) {
if (thread.getName().equals(threadName)) {
theThread = thread;
}
}

Log.d(TAG, "threadName: " + threadName

+ ", thread: " + theThread);
return theThread;
}

Ê®¡¢ ½á¹ûչʾ

¾­¹ýÖî¶à̽Ë÷£¬ÖÕÓڵõ½ÁËÍêÃÀµÄ¶ÑÕ»£º

java.lang.Error: signal 11 (Address not mapped

to object) at address 0x0
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.Error: signal 11 (Address not

mapped to object) at address 0x0
at /data/app-lib/com.tencent.moai.crashcatcher.

demo-1/libQMCrashGenerator.so.0xd8e(dangerous

Function:0x5:0)
at /data/app-lib/com.tencent.moai.crashcatcher.demo-1/libQMCrashGenerator.so.0xd95(wrapDangerou

sFunction:0x2:0)
at /data/app-lib/com.tencent.moai.crashcatcher.

demo-1/libQMCrashGenerator.so.0xd9d(nativeInvalid

AddressCrash:0x2:0)
at /system/lib/libdvm.so.0x1ee8c(dvmPlatformI

nvoke:0x70:0)
at /system/lib/libdvm.so.0x503b7(dvmCallJNI

Method(unsigned

int const*, JValue*, Method const*, Thread*):0x1ee:0)
at /system/lib/libdvm.so.0x28268(Native Method)
at /system/lib/libdvm.so.0x2f738(dvmMterpStd

(Thread*):0x44:0)
at /system/lib/libdvm.so.0x2cda8(dvmInterpret

(Thread*, Method const*, JValue*):0xb8:0)
at /system/lib/libdvm.so.0x648e3(dvmInvokeMethod

(Object*,

Method const*, ArrayObject*, ArrayObject*,

ClassObject*,

bool):0x1aa:0)
at /system/lib/libdvm.so.0x6cff9(Native Method)
at /system/lib/libdvm.so.0x28268(Native Method)
at /system/lib/libdvm.so.0x2f738(dvmMterpStd(Thread*)

:0x44:0)
at /system/lib/libdvm.so.0x2cda8(dvmInterpret(Thread*,

Method const*, JValue*):0xb8:0)
at /system/lib/libdvm.so.0x643d9(dvmCallMethodV(Thread*,

Method const*, Object*, bool, JValue*, std::__va_list):

0x14c:0)
at /system/lib/libdvm.so.0x4bca1(Native Method)
at /system/lib/libandroid_runtime.so.0x50ac3(Native

Method)
at /system/lib/libandroid_runtime.so.0x518e7(android::

AndroidRuntime::start(char const*, char const*):

0x206:0)
at /system/bin/app_process.0xf33(Native Method)
at /system/lib/libc.so.0xf584(__libc_init:0x64:0)
at /system/bin/app_process.0x107c(Native Method)
Caused by: java.lang.Error: java stack
at com.tencent.crashcatcher.CrashCatcher.nativeInvali

dAddressCrash(Native Method)
at com.tencent.crashcatcher.CrashCatcher.invalid

AddressCrash

(CrashCatcher.java:33)
at com.tencent.moai.crashcatcher.demo.MainActivity$4.

onClick

(MainActivity.java:56)
at android.view.View.performClick(View.java:4488)
at android.view.View$PerformClick.run(View.java:18860)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:222)
at android.app.ActivityThread.main(ActivityThread.

java:5484)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgs

Caller.run

(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.

java:676)
at dalvik.system.NativeStart.main(Native Method)

ÔÚnative²ã¹¹ÔìÁËÒ»¸öError´«¸øjava£¬ËùÒÔÔÚjava²ã¿ÉÒÔºÜÇáËɵظù¾Ý¶ÑÕ»½øÐÐÒµÎñÉϵĴ¦Àí¡£

public interface CrashHandleListener {
@Keep
void onCrash(int id, Error e);
}

ÁíÍâ³õʼ»¯Ê±¾Í½¨Á¢µÈ´ý»Øµ÷Ï̵߳ķ½Ê½£¬ÌṩÁËÎȶ¨µÄ¸øjava²ãµÄ»Øµ÷¡£Ôڻص÷ÖÐÎÒÃÇ´òÓ¡ÁËappµÄ״̬ÐÅÏ¢£¬°üÀ¨activityµÄ¶ÑÕ»¡¢appÊÇ·ñÔÚǰ̨µÈ£¬ÒÔ¼°´òÓ¡crashǰµÄlogcatÈÕÖ¾ºÍ°ÑÓ¦ÓÃÈÕÖ¾flush½øÎļþ¡£Õë¶ÔijЩ¾ßÌåµÄnative crash»¹×öÁËÒµÎñÉϵĴ¦Àí£¬ÀýÈçÓöµ½ÈȲ¹¶¡¿ò¼ÜÏà¹ØµÄcrashʱ¾Í»Ø¹ö²¹¶¡¡£

ÔÚÓû§»·¾³Öеĺܶànative crashµ¥¿¿¶ÑÕ»Êǽâ¾ö²»Á˵ģ¬logcatÊǷdz£ÖØÒªµÄ²¹³ä¡£ºÃ¼¸Àýwebviewcrash¶¼ÊÇͨ¹ý·¢ÉúcrashʱµÄlogcat¶¨Î»µÄ¡£±ÈÈçÎÒÃÇÔø¾­Óöµ½¹ýµÄÒ»¸öµÄwebview crash£º

#00 pc 00039874 /system/lib/libc.so (tgkill+12)
#01 pc 00013b5d /system/lib/libc.so (pthread_kill+52)
#02 pc 0001477b /system/lib/libc.so (raise+10)
#03 pc 00010ff5 /system/lib/libc.so (__libc_

android_abort+36)
#04 pc 0000f554 /system/lib/libc.so (abort+4)
#05 pc 00239885 /system/lib/libwebviewchromium.so
#06 pc 00219da3 /system/lib/libwebviewchromium.so
#07 pc 00206459 /system/lib/libwebviewchromium.so
#08 pc 001fb6c7 /system/lib/libwebviewchromium.so
#09 pc 001edc97 /system/lib/libwebviewchromium.so
#10 pc 001ec5ad /system/lib/libwebviewchromium.so
#11 pc 001ec617 /system/lib/libwebviewchromium.so
#12 pc 001ec5e5 /system/lib/libwebviewchromium.so
#13 pc 001ec5bf /system/lib/libwebviewchromium.so
#14 pc 0022c941 /system/lib/libwebviewchromium.so
#15 pc 0022c92b /system/lib/libwebviewchromium.so
#16 pc 0022e6a1 /system/lib/libwebviewchromium.so
#17 pc 0022ebcd /system/lib/libwebviewchromium.so
#18 pc 0022ee1d /system/lib/libwebviewchromium.so
#19 pc 0022c511 /system/lib/libwebviewchromium.so
#20 pc 00013347 /system/lib/libc.so (_ZL15__pthread

_startPv+30)
#21 pc 0001135f /system/lib/libc.so (__start_thread+6)

µ¥Æ¾¶ÑÕ»¸ù±¾¿´²»³öÀ´ÊÇʲôÎÊÌ⣬µ«ÊÇÔÚlogcatÖÐÈ´¿´µ½ÕâÑùÒ»¸öwarning log£ºNullPointerException£¬ ´«½øÈ¥WebViewÄÚ²¿±ä³ÉÁËnatvie crash£¬ÎÊÌâ½â¾ö¡£

05-21 15:09:28.423 W/System.err(16811): java.lang.

NullPointerException: Attempt to get length of

null array
05-21 15:09:28.424 W/System.err(16811): at java.io.ByteArrayInputStream.<init>(ByteArray

InputStream.java:60)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.fetcher.HttpImageFetcher

.fetchFrom

Network(HttpImageFetcher.java:86)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.fetcher.BaseFetcher.fetch

(BaseFetcher.

java:24)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.delaystream.DelayInput

Stream.read

(DelayInputStream.java:36)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.delaystream.DelayHttpInput

Stream.read

(DelayHttpInputStream.java:12)
05-21 15:09:28.424 W/System.err(16811): at java.io.

InputStream.

read(InputStream.java:181)
05-21 15:09:28.424 W/System.err(16811): at org.chromium.android_webview.InputStreamUtil.read

(InputStream

Util.java:54)

²é´úÂë·¢ÏÖÊÇÎÒÃÇÔÚWebViewClientµÄshouldInterceptRequest½Ó¿ÚÖеÄÒµÎñ´úÂë·¢ÉúÁËNullPointerException£¬ ´«½øÈ¥WebViewÄÚ²¿±ä³ÉÁËnatvie crash£¬ÎÊÌâ½â¾ö¡£

   
2447 ´Îä¯ÀÀ       29
Ïà¹ØÎÄÕÂ

ÊÖ»úÈí¼þ²âÊÔÓÃÀýÉè¼ÆÊµ¼ù
ÊÖ»ú¿Í»§¶ËUI²âÊÔ·ÖÎö
iPhoneÏûÏ¢ÍÆËÍ»úÖÆÊµÏÖÓë̽ÌÖ
AndroidÊÖ»ú¿ª·¢£¨Ò»£©
Ïà¹ØÎĵµ

Android_UI¹Ù·½Éè¼Æ½Ì³Ì
ÊÖ»ú¿ª·¢Æ½Ì¨½éÉÜ
androidÅÄÕÕ¼°ÉÏ´«¹¦ÄÜ
Android½²ÒåÖÇÄÜÊÖ»ú¿ª·¢
Ïà¹Ø¿Î³Ì

Android¸ß¼¶Òƶ¯Ó¦ÓóÌÐò
Androidϵͳ¿ª·¢
AndroidÓ¦Óÿª·¢
ÊÖ»úÈí¼þ²âÊÔ