導航:首頁 > 操作系統 > android自定義log

android自定義log

發布時間:2022-08-30 14:44:56

android+slog+log區別是怎麼回事

工具/原料

Eclipse
Android SDK
方法/步驟

日常Android開發真機調試過程經常會遇到系統日誌過多過快,想看的內容一閃而過的問題。而自定義些log可以很好的解決這些問題。
代碼中添加 log
androidsdk中提供了log輸出的api,方法在android.util.Log類中。
Log.v(tag,message); //verbose模式,列印最詳細的日誌
Log.d(tag,message); //debug的日誌
Log.i(tag,message); //info的日誌
Log.w(tag,message); //warn的日誌
Log.e(tag,message); //error的日誌
根據首字母對應VERBOSE,DEBUG,INFO,WARN,ERROR。
tag和message分別是兩個String值
tag用來標記log消息的源頭的. message是這條log的內容。
看代碼我這里寫了5行日誌對應不同的級別

查看log
Activity其中的中加上了Log.v來記錄日誌輸出,結果如下圖.

Eclipse指定看某個tag信息
當然我們也可以指定看某個日誌信息,具體是在Eclipse LohCat中設置需要看的tag,可見圖中紅色框體。在by Log Tag中設置先看的日誌tag。

這里我設置tag為 ,運行程序。

就可以看到指定的某個log信息了,這樣調試代碼起來是不是很方便。

② android 自定義一個log類帶有開關,debug賦值true,那什麼時候變成false

Debug和Release區別 VC下Debug和Release區別 最近寫代碼過程中,發現 Debug 下運行正常,Release 下就會出現問題,百思不得其解,而Release 下又無法進行調試,於是只能採用printf方式逐步定位到問題所在處,才發現原來是給定的一個數組未初始化,導致後面處理異常。網上查找了些資料,在這 羅列匯總下,做為備忘~ 一、Debug 和 Release 的區別 Debug 通常稱為調試版本,它包含調試信息,並且不作任何優化,便於程序員調試程序。Release 稱為發布版本,它往往是進行了各種優化,使得程序在代碼大小和運行速度上都是最優的,以便用戶很好地使用。 Debug 和 Release 的真正區別,在於一組編譯選項。 Debug 版本 參數 含義 /MDd /MLd 或 /MTd 使用 Debug runtime library(調試版本的運行時刻函數庫) /Od 關閉優化開關 /D "_DEBUG" 相當於 #define _DEBUG,打開編譯調試代碼開關(主要針對assert函數) /ZI 創建 Edit and continue(編輯繼續)資料庫,這樣在調試過程中如果修改了源代碼不需重新編譯 GZ 可以幫助捕獲內存錯誤 Release 版本 參數含義 /MD /ML 或 /MT 使用發布版本的運行時刻函數庫 /O1 或 /O2 優化開關,使程序最小或最快 /D "NDEBUG" 關閉條件編譯調試代碼開關(即不編譯assert函數) /GF 合並重復的字元串,並將字元串常量放到只讀內存,防止被修改 Debug 和 Release 並沒有本質的界限,他們只是一組編譯選項的集合,編譯器只是按照預定的選項行動。 1. 變數。 大家都知道,debug跟release在初始化變數時所做的操作是不同的,debug是將每個位元組位都賦成0xcc(注1),而release的賦值近 似於隨機(我想是直接從內存中分配的,沒有初始化過)。這樣就明確了,如果你的程序中的某個變數沒被初始化就被引用,就很有可能出現異常:用作控制變數將 導致流程導向不一致;用作數組下標將會使程序崩潰;更加可能是造成其他變數的不準確而引起其他的錯誤。所以在聲明變數後馬上對其初始化一個默認的值是最簡 單有效的辦法,否則項目大了你找都沒地方找。代碼存在錯誤在debug方式下可能會忽略而不被察覺到,如debug方式下數組越界也大多不會出錯,在 release中就暴露出來了,這個找起來就比較難了:( 還是自己多加註意吧 呵呵,就是我犯的問題~~ 2. 自定義消息的消息參數。 MFC為我們提供了很好的消息機制,更增加了自定義消息,好處我就不用多說了。這也存在debug跟release的問題嗎?答案是肯定的。在自定義消息 的函數體聲明時,時常會看到這樣的寫法:afx_msg LRESULT OnMessageOwn(); Debug情況下一般不會有任何問題,而當你在Release下且多線程或進程間使用了消息傳遞時就會導致無效句柄之類的錯誤。導致這個錯誤直接原因是消 息體的參數沒有添加,即應該寫成:afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam); (注2) 3. release模式下不出錯,但debug模式下報錯。 這種情況下大多也是因為代碼書寫不正確引起的,查看MFC的源碼,可以發現好多ASSERT的語句(斷言),這個宏只是在debug模式下才有效,那麼就 清楚了,release版不報錯是忽略了錯誤而不是沒有錯誤,這可能存在很大的隱患,因為是Debug模式下,比較方便調試,好好的檢查自己的代碼,再此 就不多說了。 4. ASSERT, VERIFY, TRACE..........調試宏 這種情況很容易解釋。舉個例子:請在VC下輸入ASSERT然後選中按F12跳到宏定義的地方,這里你就能夠發現Debug中ASSERT要執行 AfxAssertFailedLine,而Release下的宏定義卻為"#define ASSERT(f) ((void)0)"。所以注意在這些調試宏的語句不要用程序相關變數如i++寫操作的語句。VERIFY是個例外,"#define VERIFY(f) ((void)(f))",即執行,這里的作用就不多追究了,有興趣可自己研究:)。 總結: Debug與Release不同的問題在剛開始編寫代碼時會經常發生,99%是因為你的代碼書寫錯誤而導致的,所以不要動不動就說系統問題或編譯器問題, 努力找找自己的原因才是根本。我從前就常常遇到這情況,經歷過一次次的教訓後我就開始注意了,現在我所寫過的代碼我已經好久沒遇到這種問題了。下面是幾個 避免的方面,即使沒有這種問題也應注意一下: 1. 注意變數的初始化,尤其是指針變數,數組變數的初始化(很大的情況下另作考慮了)。 2. 自定義消息及其他聲明的標准寫法 3. 使用調試宏時使用後最好注釋掉 4. 盡量使用try - catch(...) 5. 盡量使用模塊,不但表達清楚而且方便調試。 注1: debug版初始化成0xcc是因為0xcc在x86下是一條int 3單步中斷指令,這樣程序如果跑飛了遇到0xcc就會停下來,這和單片機編程時一般將沒用的代碼空間填入jmp 0000語句是一樣地轉貼於:計算機二級考試_考試大【責編:drfcy 糾錯】 [VC]DEBUG和RELEASE2007年08月26日 星期日 下午 04:33 I. 內存分配問題 1. 變數未初始化。下面的程序在debug中運行的很好。 thing * search(thing * something) BOOL found; for(int i = 0; i < whatever.GetSize(); i++) { if(whatever[i]->field == something->field) { /* found it */ found = TRUE; break; } /* found it */ } if(found) return whatever[i]; else return NULL; 而在release中卻不行,因為debug中會自動給變數初始化found=FALSE,而在release版中則不會。所以盡可能的給變數、類或結構初始化。 2. 數據溢出的問題 如:char buffer[10]; int counter; lstrcpy(buffer, "abcdefghik"); 在debug版中buffer的NULL覆蓋了counter的高位,但是除非counter>16M,什麼問題也沒有。但是在release版 中,counter可能被放在寄存器中,這樣NULL就覆蓋了buffer下面的空間,可能就是函數的返回地址,這將導致ACCESS ERROR。 3. DEBUG版和RELEASE版的內存分配方式是不同的 。如果你在DEBUG版中申請 ele 為 6*sizeof(DWORD)=24bytes,實際上分配給你的是32bytes(debug版以32bytes為單位分配), 而在release版,分配給你的就是24bytes(release版以8bytes為單位),所以在debug版中如果你寫ele[6],可能不會有 什麼問題,而在release版中,就有ACCESS VIOLATE。 II. ASSERT和VERIFY 1. ASSERT在Release版本中是不會被編譯的。 ASSERT宏是這樣定義的 #ifdef _DEBUG #define ASSERT(x) if( (x) == 0) report_assert_failure() #else #define ASSERT(x) #endif 實際上復雜一些,但無關緊要。假如你在這些語句中加了程序中必須要有的代碼 比如 ASSERT(pNewObj = new CMyClass); pNewObj->MyFunction(); 這種時候Release版本中的pNewObj不會分配到空間 所以執行到下一個語句的時候程序會報該程序執行了非法操作的錯誤。這時可以用VERIFY : #ifdef _DEBUG #define VERIFY(x) if( (x) == 0) report_assert_failure() #else #define VERIFY(x) (x) #endif 這樣的話,代碼在release版中就可以執行了。 III. 參數問題: 自定義消息的處理函數,必須定義如下: afx_msg LRESULT OnMyMessage(WPARAM, LPARAM); 返回值必須是HRESULT型,否則Debug會過,而Release出錯 IV. 內存分配 保證數據創建和清除的統一性:如果一個DLL提供一個能夠創建數據的函數,那麼這個DLL同時應該提供一個函數銷毀這些數據。數據的創建和清除應該在同一個層次上。 V. DLL的災難 人們將不同版本DLL混合造成的不一致性形象的稱為 「動態連接庫的地獄「(DLL Hell) ,甚至微軟自己也這么說 如果你的程序使用你自己的DLL時請注意: 1. 不能將debug和release版的DLL混合在一起使用。debug都是debug版,release版都是release版。 解決辦法是將debug和release的程序分別放在主程序的debug和release目錄下 2. 千萬不要以為靜態連接庫會解決問題,那隻會使情況更糟糕。 VI. RELEASE板中的調試 : 1. 將ASSERT() 改為 VERIFY() 。找出定義在"#ifdef _DEBUG"中的代碼,如果在RELEASE版本中需要這些代碼請將他們移到定義外。查找TRACE(...)中代碼,因為這些代碼在RELEASE中 也不被編譯。 請認真檢查那些在RELEASE中需要的代碼是否並沒有被便宜。 2. 變數的初始化所帶來的不同,在不同的系統,或是在DEBUG/RELEASE版本間都存在這樣的差異,所以請對變數進行初始化。 3. 是否在編譯時已經有了警告?請將警告級別設置為3或4,然後保證在編譯時沒有警告出現. VII. 將Project Settings" 中 "C++/C " 項目下優化選項改為Disbale(Debug)。編譯器的優化可能導致許多意想不到的錯誤 1. 此外對RELEASE版本的軟體也可以進行調試,請做如下改動: 在"Project Settings" 中 "C++/C " 項目下設置 "category" 為 "General" 並且將"Debug Info"設置為 "Program Database"。 在"Link"項目下選中"Generate Debug Info"檢查框。 "Rebuild All" 如此做法會產生的一些限制: 無法獲得在MFC DLL中的變數的值。 必須對該軟體所使用的所有DLL工程都進行改動。

③ Android studio怎麼自定義logcat提示信息

一、下載安裝 下載後,打開並將Android Studio拖動到Applications中去,拷貝完畢即可,可以到應用程序下將圖標拖動到Dock上。 二、新建工程 安裝完成後,選擇默認選項點擊OK即可: 進入Android Studio,開始界面和Xcode有點類似,點擊New project新建一個工程,新建過程和在Eclipse上差不多。 新建工程完畢後就進入了Android Studio主界面。第一次進去可能什麼也沒有,點擊箭頭所示按鈕目錄結構, 後可以看到Android Studio的目錄結構,和Eclipse的工程還是有一點區別的: 區別: 1.Android Studio的目錄結構本來就代表一個workspace,一個workspace裡面可以有Mole,可以將一個Mole理解成Eclipse中的一個Project; 2.目錄中將java代碼和資源文件(圖片、布局文件等)全部歸結為src,在src目錄下有一個main的分組,同時劃分出java和res兩個Group,res和Eclipse下的結構一樣,java下就是源碼的包和類文件; 3.新建文件方式的不同,右鍵選擇New或Command+N後出現新建菜單,類型有Java Class,也就是一般的java類,File就是普通文件,Package就是建包,值得注意的就是Android Component,它直接提供了Android中基本組件的創建。 可以選擇創建Android中不同類型的組件: 三、窗口布局及主題介紹 另外,主界面底部有一個名為Android的選項卡,打開可以看到DDMS中的設備信息和Logcat輸出: 頂部工具欄中可以看到和Eclipse中功能一樣的一個選項,這些相信大家都比較熟悉了: 最後需要說明的是,大家看到我的主界面是暗色風格,和Google演示的是一樣的風格,大家第一次使用打開的是默認風格(亮色),如果想要修改的話,進入Preferences(按Command+,)到IDE Settings下選擇Colors&font並設置Schema name為Darcula就可以設置成暗色風格,如果需要自己定義樣式,比如字體大小顏色等,可以新建一個Schema來自己定義 四、布局文件編寫(實時預覽) 最炫的功能要來了,實時編寫並預覽布局文件,此項功能著實大大提高開發效率,打開一個xml布局文件點擊右側Preview選項卡即可喚出預覽界面,可以選擇很多尺寸的手機進行預覽: 同時,還可以同時預覽多種不同型號和尺寸的設備,編寫代碼的同時適配多種機型,這不就是當初夢寐以求的嘛! 上面介紹了Android Studio的基本使用,包括安裝、新建工程、工程結構以及主題設置。下面介紹一些其他技巧,以及與Eclipse之前的一些對比。需要重申一下,我所有的操作與版本是基於Mac系統,在Windows上的同學基本類似,下面就分主題開始吧: 一、從Eclipse導入工程到Android Studio 根據官方的介紹,Android Studio可以兼容Eclipse的現有工程,但需要做一些操作: 首先升級ADT到最新版本,目前為版本號為22(注意和ADT相關的組件最好一並升級,避免後期可能出現的錯誤) 選擇需要從Eclipse導出的工程,右鍵選擇Export並選擇Android下的Generate Gradle Build Files 選擇完畢後並不會導出到其他地方,而是在本地工程生成了一個build.gradle文件,在Eclipse工程中也可以看到,這個文件是Android Studio識別的 3.隨後進入Android Studio並選擇Import Project,可以看到剛剛在Eclipse中的項目圖標變成了一個Android機器人圖標,說明轉換成功,這時候選擇工程導入即可: 至此,就完成了從Eclipse導入現有Android工程到Android Studio,現在可以開始對工程進行操作了! 二、Eclipse工程與Android Studio的區別 Eclipse工程可以導入Android Studio運行,而反過來在Android Studio建立的工程不能在Eclipse中運行; 二者的工程結構不一樣,在Eclipse中一個Project就代表一個項目工程,而在Android Studio中就和Intellij一樣,一個Project代表一個工作空間,相當於Eclipse中的workspace,而在Android Studio中一個Mole就相當於Eclipse中的一個Project,這個概念需要弄明白,不要混了或覺得糊塗了。 在編輯操作上,在Eclipse中編輯修改後必須手動command+s保存文件,而在Android Studio中就和Intellij一樣是自動保存的,這一點和第二點和Xcode也是類似的。 工程目錄上的區別,在Eclipse中src部分一般是java文件,res部分是資源文件,包括布局文件和多媒體資源等。在Android Studio中 包括java文件和資源文件全部放到了src目錄下,src目錄下包括一個main文件夾,再下面就是java文件夾和res文件夾,其實這里,java文件夾就相當於Eclipse中的src,res還是那個res,這里想起了本山老師的小品「src已經不是那個src了,res還是那個res」 三、真機運行以及常用快捷鍵 在Android Studio中點擊界面下方的Android選項卡可以看到Device信息和Logcat,連上設備後打開Android選項卡會檢測真機,成功後會顯示在Device中,點擊頂部的綠色小箭頭就可以開始運行工程了。有一點需要注意的是,運行時可以選擇模擬器也可以選擇真機,由於在Android Studio中運行工程的時候有一個Device優先順序選擇,如果不設置的話可能會出現只運行在模擬器上的現象,我們可以自行設置一下:先點擊Run菜單選擇Run Configuration,並選擇你想選擇的目標設備,可以是模擬器和真機,也可以在運行選由用戶選擇: 快捷鍵大家可以對照官方文檔進行熟悉,如下表,也可以自己修改配置選項進行自定義: 個人覺得Android Studio還是有一定的前景的,這里就需要Google不斷進行完善和改進了,趕緊把大家從Eclipse中解救出來吧。另外,在此期間,大家其實可以嘗試使用一下Intellij IDEA,這個默認也是集成Android開發環境的。Android Studio是基於前者改進而來,二者在使用上差不多,也是Eclipse的一個不錯的替代者。

④ 如何實現一個android的log自動化分析工具

首先,讓我們看一看AndroidLog的格式。下面這段log是以所謂的long格式列印出來的。從前面Logcat的介紹中可以知道,long格式會把時間,標簽等作為單獨的一行顯示。

[ 12-09 21:39:35.510 396: 416 I/ActivityManager ]

Start procnet.coollet.infzmreader:umengService_v1 for service
net.coollet.infzmreader/com.umeng.message.

UmengService:pid=21745 uid=10039 gids={50039, 3003, 1015,1028}

[ 12-09 21:39:35.518 21745:21745I/dalvikvm ]

Turning on JNI app bug workarounds fortarget SDK version 8...

[ 12-09 21:39:35.611 21745:21745D/AgooService ]

onCreate()

我們以第一行為例:12-09 是日期,21:39:35.510是時間396是進程號,416是線程號;I代表log優先順序,ActivityManager是log標簽。

在應用開發中,這些信息的作用可能不是很大。但是在系統開發中,這些都是很重要的輔助信息。開發工程師分析的log很多都是由測試工程師抓取的,所以可能有些log根本就不是當時出錯的log。如果出現這種情況,無論你怎麼分析都不太可能得出正確的結論。如何能最大限度的避免這種情況呢?筆者就要求測試工程師報bug時必須填上bug發生的時間。這樣結合log里的時間戳信息就能大致判斷是否是發生錯誤時的log。而且根據測試工程師提供的bug發生時間點,開發工程師可以在長長的log信息中快速的定位錯誤的位置,縮小分析的范圍。

同時我們也要注意,時間信息在log分析中可能被錯誤的使用。例如:在分析多線程相關的問題時,我們有時需要根據兩段不同線程中log語句執行的先後順序來判斷錯誤發生的原因,但是我們不能以兩段log在log文件中出現的先後做為判斷的條件,這是因為在小段時間內兩個線程輸出log的先後是隨機的,log列印的先後順序並不完全等同於執行的順序。那麼我們是否能以log的時間戳來判斷呢?同樣是不可以,因為這個時間戳實際上是系統列印輸出log時的時間,並不是調用log函數時的時間。遇到這種情況唯一的辦法是在輸出log前,調用系統時間函數獲取當時時間,然後再通過log信息列印輸出。這樣雖然麻煩一點,但是只有這樣取得的時間才是可靠的,才能做為我們判斷的依據。

另外一種誤用log中時間戳的情況是用它來分析程序的性能。一個有多年工作經驗的工程師拿著他的性能分析結果給筆者看,但是筆者對這份和實際情況相差很遠的報告表示懷疑,於是詢問這位工程師是如何得出結論的。他的回答讓筆者很驚訝,他計算所採用的數據就是log信息前面的時間戳。前面我們已經講過,log前面時間戳和調用log函數的時間並不相同,這是由於系統緩沖log信息引起的,而且這兩個時間的時間差並不固定。所以用log信息前附帶的時間戳來計算兩段log間代碼的性能會有比較大的誤差。正確的方法還是上面提到的:在程序中獲取系統時間然後列印輸出,利用我們列印的時間來計算所花費的時間。

了解了時間,我們再談談進程Id和線程Id,它們也是分析log時很重要的依據。我們看到的log文件,不同進程的log信息實際上是混雜在一起輸出的,這給我們分析log帶來了很大的麻煩。有時即使是一個函數內的兩條相鄰的log,也會出現不同進程的log交替輸出的情況,也就是A進程的第一條log後面跟著的是B進程的第二條log,對於這樣的組合如果不細心分析,就很容易得出錯誤的結論。這時一定要仔細看log前面的進程Id,把相同Id的log放到一起看。

不同進程的log有這樣的問題,不同的線程輸出的log當然也存在著相同的問題。Logcat加上-vthread就能列印出線程Id。但是有一點也要引起注意,就是Android的線程Id和我們平時所講的linux線程Id並不完全等同。首先,在Android系統中,C++層使用的Linux獲取線程Id的函數gettid()是不能得到線程Id的,調用gettid()實際上返回的是進程Id。作為替代,我們可以調用pthread_self()得到一個唯一的值來標示當前的native線程。Android也提供了一個函數androidGetThreaId()來獲取線程Id,這個函數實際上就是在調用pthread_self函數。但是在Java層線程Id又是另外一個值,Java層的線程Id是通過調用Thread的getId方法得到的,這個方法的返回值實際上來自Android在每個進程的java層中維護的一個全局變數,所以這個值和C++層所獲得的值並不相同。這也是我們分析log時要注意的問題,如果是Java層線程Id,一般值會比較小,幾百左右;如果是C++層的線程,值會比較大。在前裡面的log樣本中,就能很容易的看出,第一條log是Jave層輸出的log,第二條是native層輸出的。明白了這些,我們在分析log時就不要看見兩段log前面的線程Id不相同就得出是兩個不同線程log的簡單結論,還要注意Jave層和native層的區別,這樣才能防止被誤導。

AndroidLog的優先順序在列印輸出時會被轉換成V,I,D,W,E等簡單的字元標記。在做系統log分析時,我們很難把一個log文件從頭看到尾,都是利用搜索工具來查找出錯的標記。比如搜索「E/」來看看有沒有指示錯誤的log。所以如果參與系統開發的每個工程師都能遵守Android定義的優先順序含義來輸出log,這會讓我們繁重的log分析工作變得相對輕鬆些。

Android比較常見的嚴重問題有兩大類,一是程序發生崩潰;二是產生了ANR。程序崩潰和ANR既可能發生在java層,也可能發生在native層。如果問題發生在java層,出錯的原因一般比較容易定位。如果是native層的問題,在很多情況下,解決問題就不是那麼的容易了。我們先看一個java層的崩潰例子:

I/ActivityManager( 396): Start proccom.test.crash for activity com.test.crash/.MainActivity:
pid=1760 uid=10065 gids={50065, 1028}

D/AndroidRuntime( 1760): Shutting downVM

W/dalvikvm( 1760): threadid=1: threadexiting with uncaught exception(group=0x40c38930)

E/AndroidRuntime( 1760): FATALEXCEPTION: main

E/AndroidRuntime( 1760):java.lang.RuntimeException: Unable to start activityComponentInfo
{com.test.crash/com.test.crash.MainActivity}:java.lang.NullPointerException

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.access$600(ActivityThread.java:141)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)

E/AndroidRuntime( 1760): atandroid.os.Handler.dispatchMessage(Handler.java:99)

E/AndroidRuntime( 1760): atandroid.os.Looper.loop(Looper.java:137)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.main(ActivityThread.java:5050)

E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invokeNative(NativeMethod)

E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invoke(Method.java:511)

E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:793)

E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)

E/AndroidRuntime( 1760): atdalvik.system.NativeStart.main(NativeMethod)

E/AndroidRuntime( 1760): Caused by:java.lang.NullPointerException

E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.setViewText(MainActivity.java:29)

E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.onCreate(MainActivity.java:17)

E/AndroidRuntime( 1760): atandroid.app.Activity.performCreate(Activity.java:5104)

E/AndroidRuntime( 1760): atandroid.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)

E/AndroidRuntime( 1760): ... 11more

I/Process ( 1760): Sending signal.PID: 1760 SIG: 9

W/ActivityManager( 396): Force finishing activitycom.test.crash/.MainActivity

Jave層的代碼發生crash問題時,系統往往會列印出很詳細的出錯信息。比如上面這個例子,不但給出了出錯的原因,還有出錯的文件和行數。根據這些信息,我們會很容易的定位問題所在。native層的crash雖然也有棧log信息輸出,但是就不那麼容易看懂了。下面我們再看一個native層crash的例子:

F/libc ( 2102): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread2102 (testapp)

D/dalvikvm(26630):GC_FOR_ALLOC freed 604K, 11% free 11980K/13368K, paused 36ms, total36ms

I/dalvikvm-heap(26630):Grow heap (frag case) to 11.831MB for 102416-byteallocation

D/dalvikvm(26630):GC_FOR_ALLOC freed 1K, 11% free 12078K/13472K, paused 34ms, total34ms

I/DEBUG ( 127):*** *** *** *** *** *** *** *** *** *** *** *** *** *** ******

I/DEBUG ( 127):Build fingerprint:
'Android/full_maguro/maguro:4.2.2/JDQ39/eng.liuchao.20130619.201255:userdebug/test-keys'

I/DEBUG ( 127):Revision: '9'

I/DEBUG ( 127):pid: 2102, tid: 2102, name: testapp >>>./testapp <<<
I/DEBUG ( 127):signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr00000000

I/DEBUG ( 127): r0 00000020 r173696874 r2 400ff520 r300000000

I/DEBUG ( 127): r4 400ff469 r5beb4ab24 r6 00000001 r7beb4ab2c

I/DEBUG ( 127): r8 00000000 r900000000 sl 00000000 fpbeb4ab1c

I/DEBUG ( 127): ip 4009b5dc spbeb4aae8 lr 400ff46f pc400ff45e cpsr 60000030

I/DEBUG ( 127): d0 000000004108dae8 d1 4108ced84108cec8

I/DEBUG ( 127): d2 4108cef84108cee8 d3 4108cf184108cf08

I/DEBUG ( 127): d4 4108c5a84108c598 d5 4108ca084108c5b8

I/DEBUG ( 127): d6 4108ce684108ce58 d7 4108ce884108ce78

I/DEBUG ( 127): d8 0000000000000000 d9 0000000000000000

I/DEBUG ( 127): d10 0000000000000000 d110000000000000000

I/DEBUG ( 127): d120000000000000000 d130000000000000000

I/DEBUG ( 127): d14 0000000000000000 d150000000000000000

I/DEBUG ( 127): d16 c1dcf7c087fec8b4 d173f50624dd2f1a9fc

I/DEBUG ( 127): d18 41c7b1ac89800000 d190000000000000000

I/DEBUG ( 127): d20 0000000000000000 d210000000000000000

I/DEBUG ( 127): d22 0000000000000000 d230000000000000000

I/DEBUG ( 127): d24 0000000000000000 d250000000000000000

I/DEBUG ( 127): d26 0000000000000000 d270000000000000000

I/DEBUG ( 127): d28 0000000000000000 d290000000000000000

I/DEBUG ( 127): d30 0000000000000000 d310000000000000000

I/DEBUG ( 127): scr 00000010

I/DEBUG ( 127):

I/DEBUG ( 127):backtrace:

I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

I/DEBUG ( 127):

I/DEBUG ( 127):stack:

I/DEBUG ( 127): beb4aaa8 000000c8
I/DEBUG ( 127): beb4aaac 00000000
I/DEBUG ( 127): beb4aab0 00000000
I/DEBUG ( 127): beb4aab4 401cbee0 /system/bin/linker

I/DEBUG ( 127): beb4aab8 00001000
I/DEBUG ( 127): beb4aabc 4020191d /system/lib/libc.so (__libc_fini)

I/DEBUG ( 127): beb4aac0 4020191d /system/lib/libc.so (__libc_fini)

I/DEBUG ( 127): beb4aac4 40100eac /system/bin/testapp

I/DEBUG ( 127): beb4aac8 00000000
I/DEBUG ( 127): beb4aacc 400ff469 /system/bin/testapp

I/DEBUG ( 127): beb4aad0 beb4ab24 [stack]

I/DEBUG ( 127): beb4aad4 00000001
I/DEBUG ( 127): beb4aad8 beb4ab2c [stack]

I/DEBUG ( 127): beb4aadc 00000000
I/DEBUG ( 127): beb4aae0 df0027ad
I/DEBUG ( 127): beb4aae4 00000000
I/DEBUG ( 127): #00 beb4aae8 00000000
I/DEBUG ( 127): ........ ........

I/DEBUG ( 127): #01 beb4aae8 00000000
I/DEBUG ( 127): beb4aaec 401e9721 /system/lib/libc.so (__libc_init+40)

I/DEBUG ( 127): #02 beb4aaf0 beb4ab08 [stack]

I/DEBUG ( 127): beb4aaf4 00000000
I/DEBUG ( 127): beb4aaf8 00000000
I/DEBUG ( 127): beb4aafc 00000000
I/DEBUG ( 127): beb4ab00 00000000
I/DEBUG ( 127): beb4ab04 400ff404 /system/bin/testapp

I/DEBUG ( 127):

這個log就不那麼容易懂了,但是還是能從中看出很多信息,讓我們一起來學習如何分析這種log。首先看下面這行:

pid: 2102, tid: 2102,name: testapp >>>./testapp <<<
從這一行我們可以知道crash進程的pid和tid,前文我們已經提到過,Android調用gettid函數得到的實際是進程Id號,所以這里的pid和tid相同。知道進程號後我們可以往前翻翻log,看看該進程最後一次列印的log是什麼,這樣能縮小一點范圍。

接下來內容是進程名和啟動參數。再接下來的一行比較重要了,它告訴了我們從系統角度看,出錯的原因:

signal 11 (SIGSEGV), code 1(SEGV_MAPERR), fault addr 00000000

signal11是Linux定義的信號之一,含義是Invalidmemory reference,無效的內存引用。加上後面的「faultaddr 00000000」我們基本可以判定這是一個空指針導致的crash。當然這是筆者為了講解而特地製造的一個Crash的例子,比較容易判斷,大部分實際的例子可能就沒有那麼容易了。

再接下來的log列印出了cpu的所有寄存器的信息和堆棧的信息,這裡面最重要的是從堆棧中得到的backtrace信息:

I/DEBUG ( 127):backtrace:

I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

因為實際的運行系統里沒有符號信息,所以列印出的log里看不出文件名和行數。這就需要我們藉助編譯時留下的符號信息表來翻譯了。Android提供了一個工具可以來做這種翻譯工作:arm-eabi-addr2line,位於prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin目錄下。用法很簡單:

#./arm-eabi-addr2line -f -eout/target/proct/hammerhead/symbols/system/bin/testapp0x0000045e

參數-f表示列印函數名;參數-e表示帶符號表的模塊路徑;最後是要轉換的地址。這條命令在筆者的編譯環境中得到的結果是:

memcpy /home/rd/compile/android-4.4_r1.2/bionic/libc/include/string.h:108

剩餘三個地址翻譯如下:

main /home/rd/compile/android-4.4_r1.2/packages/apps/testapp/app_main.cpp:38

out_vformat /home/rd/compile/android-4.4_r1.2/bionic/libc/bionic/libc_logging.cpp:361

_start libgcc2.c:0

利用這些信息我們很快就能定位問題了。不過這樣手動一條一條的翻譯比較麻煩,筆者使用的是從網上找到的一個腳本,可以一次翻譯所有的行,有需要的讀者可以在網上找一找。

了解了如何分析普通的Log文件,下面讓我們再看看如何分析ANR的Log文件。

⑤ android開發怎麼使用log

這個問題問的過於籠統了,給你做個截圖說明幾點吧

  1. 這張圖是過濾log信息用的,可以自定義log的tag,一般都是程序中log的tag,類似

    private static final String tag = "WebActivity";

    暫時就這吧

⑥ Android studio怎麼自定義logcat提示信息

進行點擊android studio菜單中的file的選項之後,彈出了下拉菜單中進行選擇為「settings」的選項。

進入到了settings的選項框中,進行選中列表中的editor的選項。

進行點擊editor的會展開,進行點擊android logcat的選項。

由於默認的設置是不能修改的所以需要自己進行創建,進行點擊save as的選項,需要輸入文件名,名字可以隨意去

新建的android logcat還是不能直接修改,把use inherited attribute的溝去掉。

這些設置主要進行設置顏色的選項,進行點擊顏色按鈕。

彈出了select color的窗口之後,進行選擇需要的顏色,然後進行點擊choose。

可以看到assert在logcat預覽中顯示為深藍的顏色。其它設置的設置也是類似。

⑦ Android中怎麼控制LogCat的自定義輸出

你好!首先log有很多類型
log.v(String tag,String msg); // 冗餘消息
log.d(String tag,String msg); // 調試消息
log.i(String tag,String msg); // 普通消息
log.w(String tag,String msg); //警告消息
log.e(String tag,String msg); // 錯誤消息
關於您說的建立一個log的tag,可用如下語句來實現
private static final String TAG="此處寫您要設置的tag"

然後再程序中我一般用的是Log.v(TAG,"想列印的信息")
這樣的話,在logcat中就可以顯示出自定義的TAG

⑧ 實現android開機自動生成log的腳本

用廣播接收者,接收開機廣播,然後在廣播里開啟一條服務
在服務里寫對log文件的寫出就行了
開機廣播為:
<action android:name="android.intent.action.BOOT_COMPLETED" />

閱讀全文

與android自定義log相關的資料

熱點內容
丟失微信app怎麼找 瀏覽:248
php能寫前端嗎 瀏覽:3
伺服器如何更改raid模式 瀏覽:82
方舟伺服器怎麼導出來 瀏覽:606
手機顯示伺服器異常什麼鬼 瀏覽:377
新聞伺服器的網址是什麼 瀏覽:665
程序員年底招人 瀏覽:311
廣發app怎麼查房貸 瀏覽:856
安卓手機怎麼下土豆 瀏覽:919
只有一個app顯示網路異常怎麼回事 瀏覽:988
解壓玩具是水寶寶 瀏覽:817
壓縮機保護怎麼解決 瀏覽:944
單片機簡易電子時鍾 瀏覽:402
pdf影印版 瀏覽:689
單片機的中斷技術 瀏覽:626
表格加密才能打開 瀏覽:39
多態可以提高編譯可靠性嗎 瀏覽:599
拼好魔方的app怎麼下載 瀏覽:503
江蘇金稅盤測試伺服器地址是什麼 瀏覽:607
螺桿式壓縮冷凝機組 瀏覽:299