㈠ android P 系統穩定性問題分析方法總結
Android系統最開始是為手機設計的,在機頂盒,電視,帶屏音箱等大屏上運行後,晶元廠家做些適配,產品廠家也會做系統客制化,有時候還要適配第三方應用..等待
這種適配容易引人系統的穩定性問題,系統穩定性對於用戶體驗至關重要,很多問題也都比較類似,android系統對系統性能,穩定性分析工具也比較多,下面根據工作中遇到的問題做個總結。
從表現來看有: 死機重啟, 自動關機, 無法開機,凍屏,黑屏以及閃退, 無響應等情況;
從技術層面來劃分無外乎兩大類: 長時間無法執行完成(Timeout) 以及異常崩潰(crash). 主要分類如下:
ANR(Application Not responding),是指普通app進程超過一定時間沒有執行完,系統會彈出應用無響應對話框. 如果
該進程運行在system進程, 更准確的來說,應該是(System Not Responding, SNR)
ANR產生的原因可能是各種各樣的,但常見的原因可以分為:
1.logcat日誌
2.trace文件(保存在/data/anr/traces.txt)
從logcat里可以看到死鎖的列印
從traces.txt可以看到線程的函數調用棧
10-16 00:50:10 820 907 E ActivityManager: ANR in com.android.systemui, time=130090695
10-16 00:50:10 820 907 E ActivityManager: Reason: Broadcast of Intent { act=android.intent.action.TIME_TICK flg=0x50000114 (has extras) }
10-16 00:50:10 820 907 E ActivityManager: Load: 30.4 / 22.34 / 19.94
10-16 00:50:10 820 907 E ActivityManager: Android time :[2015-10-16 00:50:05.76] [130191,266]
10-16 00:50:10 820 907 E ActivityManager: CPU usage from 6753ms to -4ms ago:
10-16 00:50:10 820 907 E ActivityManager: 47% 320/netd: 3.1% user + 44% kernel / faults: 14886 minor 3 major
10-16 00:50:10 820 907 E ActivityManager: 15% 10007/com.sohu.sohuvideo: 2.8% user + 12% kernel / faults: 1144 minor
10-16 00:50:10 820 907 E ActivityManager: 13% 10654/hif_thread: 0% user + 13% kernel
10-16 00:50:10 820 907 E ActivityManager: 11% 175/mmcqd/0: 0% user + 11% kernel
10-16 00:50:10 820 907 E ActivityManager: 5.1% 12165/app_process: 1.6% user + 3.5% kernel / faults: 9703 minor 540 major
10-16 00:50:10 820 907 E ActivityManager: 3.3% 29533/com.android.systemui: 2.6% user + 0.7% kernel / faults: 8402 minor 343 major
......
10-16 00:50:10 820 907 E ActivityManager: +0% 12832/cat: 0% user + 0% kernel
10-16 00:50:10 820 907 E ActivityManager: +0% 13211/zygote64: 0% user + 0% kernel
10-16 00:50:10 820 907 E ActivityManager: 87% TOTAL: 3% user + 18% kernel + 64% iowait + 0.5% softirq
發生ANR的時間 00:50:10 ,可以從這個時間點之前的日誌中,還原ANR出現時系統的運行狀態
發生ANR的進程 com.android.system.ui
發生ANR的原因 Reason關鍵字表明了ANR的原因是處理TIME_TICK廣播消息超時
CPU負載 Load關鍵字表明了最近1分鍾、5分鍾、15分鍾內的CPU負載分別是30.4、22.3、19.94.CPU最近1分鍾的負載最具參考價值,因為ANR的超時限制基本都是1分鍾以內, 這可以近似的理解為CPU最近1分鍾平均有30.4個任務要處理,這個負載值是比較高的
CPU使用統計時間段 CPU usage from XX to XX ago關鍵字表明了這是在ANR發生之前一段時間內的CPU統計,類似的還有CPU usage from XX to XX after關鍵字,表明是ANR發生之後一段時間內的CPU統計
各進程的CPU使用率
以com.android.systemui進程的CPU使用率為例,它包含以下信息:
總的CPU使用率: 3.3%,其中systemui進程在用戶態的CPU使用率是2.6%,在內核態的使用率是0.7%
缺頁次數fault:8402 minor表示高速緩存中的缺頁次數,343 major表示內存的缺頁次數。minor可以理解為進程在做內存訪問,major可以理解為進程在做IO操作。 當前minor和major值都是比較高的,從側面反映了發生ANR之前,systemui進程有有較多的內存訪問操作,引發的IO次數也會較多
CPU使用匯總 TOTAL關鍵字表明了CPU使用的匯總,87%是總的CPU使用率,其中有一項iowait表明CPU在等待IO的時間,佔到64%,說明發生ANR以前,有大量的IO操作。app_process、 system_server, com.android.systemui這幾個進程的major值都比較大,說明這些進程的IO操作較為頻繁,從而拉升了整個iowait的時間
traces.txt 如下
----- pid 29533 at 2015-10-16 00:48:29 -----
Cmd line: com.android.systemui
DALVIK THREADS (54):
"main" prio=5 tid=1 Blocked
| group="main" sCount=1 dsCount=0 obj=0x75bd5818 self=0x7f8549a000
| sysTid=29533 nice=0 cgrp=bg_non_interactive sched=0/0 handle=0x7f894bbe58
| state=S schedstat=( 289080040422 93461978317 904874 ) utm=20599 stm=8309 core=0 HZ=100
| stack=0x7fdffda000-0x7fdffdc000 stackSize=8MB
| held mutexes=
at com.mediatek.anrappmanager.MessageLogger.println(SourceFile:77)
Android系統中,有硬體WatchDog用於定時檢測關鍵硬體是否正常工作,類似地,在framework層有一個軟體WatchDog用於定期檢測關鍵系統服務是否發生死鎖事件。
watchdog 每過30s 檢測一次, 如果要監控的線程30s 後沒有響應,系統會mp出此進程堆棧,如果超過60s 沒有相應,會觸發watchdog,並重啟系統
10:57:23.718 579 1308 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.server.am.ActivityManagerService on foreground thread (android.fg), Blocked in handler on main thread (main), Blocked in handler on ActivityManager (ActivityManager)
10:57:23.725 579 1308 W Watchdog: android.fg annotated stack trace:
10:57:23.726 579 1308 W Watchdog: at com.android.server.am.ActivityManagerService.monitor(ActivityManagerService.java:26271)
10:57:23.727 579 1308 W Watchdog: - waiting to lock <0x0bb47e39> (a com.android.server.am.ActivityManagerService)
10:57:23.727 579 1308 W Watchdog: at com.android.server.Watchdog DeliveryTracker.alarmTimedOut(AlarmManagerService.java:4151)
10:57:23.733 579 1308 W Watchdog: - waiting to lock <0x00aaee38> (a java.lang.Object)
......
10:57:23.736 579 1308 W Watchdog: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:838)
10:57:23.739 579 1308 W Watchdog: ActivityManager annotated stack trace:
10:57:23.740 579 1308 W Watchdog: at com.android.server.am.ActivityStack$ActivityStackHandler.handleMessage(ActivityStack.java:405)
10:57:23.740 579 1308 W Watchdog: - waiting to lock <0x0bb47e39> (a com.android.server.am.ActivityManagerService)
10:57:23.740 579 1308 W Watchdog: at android.os.Handler.dispatchMessage(Handler.java:106)
10:57:23.741 579 1308 W Watchdog: *** GOODBYE!
分析:
提示 ActivityManagerService的android.fg,main,ActivityManager 線程Block了,但logcat里只能看到
android.fg等待0x0bb47e39 鎖,main 等待0x00aaee38鎖,ActivityManager等待0x0bb47e39鎖,無法進一步分析,需要看traces.txt
Cmd line: system_server
......
"main" prio=5 tid=1 Blocked
當出現應用閃退,可以從兩個方面查看:
1、是否應用崩潰:
可以通過logcat –s AndroidRuntime DEBUG過濾日誌,查看應用奔潰的具體堆棧信息。
其中AndroidRuntime的TAG列印java層信息,DEBUG的TAG列印native層的信息。
2、是否被lowmemorykiller殺掉:
可以通過 logcat –s lowmemorykiller 過濾日誌,注意adj 0是代表前台進程。例如:
03-08 04:16:58.084 310 310 I lowmemorykiller: Killing'com.google.android.tvlauncher' (2520), uid 10007, adj 0
發生這種情況,需要mpsys meminfo 查看當前內存狀態,是否有進程內存泄漏,導致系統內存不夠,出現前台進程被殺,造成閃退。
測試過程中,經常遇到屏幕閃爍的現象,需要排除是OSD層閃爍,還是video層閃爍。
1、先通過android原生方法:screencap截圖, screenrecord 錄制視頻,這里都是截取的OSD層,查看是否有閃屏現象。
2、OSD沒有問題,就需要從更底層的顯示模塊分析,一般需要晶元廠家提供debug手段,不同晶元廠家方案不一樣。
3, 有時候輸出不穩定,hdmi/mipi信號干擾,輸出頻率異常等也會導致閃屏,這種情況需要硬體協助分析。
如果OSD層也閃爍,則需從系統和應用層面分析。如曾遇到在開機向導界面,有個應用不斷被喚起,導致走開機向導時出現連續閃灰屏的現象。
黑屏分UI黑屏,視頻播放黑屏但UI正常等,2種場景
1、screencap截屏,排查OSD層圖形是否正常,
2、如果OSD圖形正常,需要排查顯示輸出模塊是否異常。
3、電視機裡面屏顯是單獨控制,如果屏參配置錯誤會導致整改黑屏。
OSD異常,需要排查頂層activity是否黑屏,window是否有異常等.
1,排查視頻圖層或者window是否創建成功。
2,排查解碼是否有異常,不同的應用youtube,netflix,iptv解碼方式不一樣,需要具體問題具體分析。
如下,ActivityManager因為空對象引用而掛掉,導致system_server重啟
*** [FATAL EXCEPTION IN SYSTEM PROCESS: ActivityHanager [
^ava.lang.NullPointerException: Attempt to invoke virtual method 'void co®.android.internal.os.KernelSingleUidTimeReader.iBarkDataAsStale(boolean)' on a null object reference
at com.android.internal.os.BatteryStatsIiaplSConstants.(BatteryStatslnpl.java:13355)
at com.android.internal.os.BatteryStatsInplSConstants.upddteConstants(BatteryStatsImpl.java:13330)
at com.android.internal-o-batteryStatslMpl$Constants-onChange(BatteryStatsInpl-java:13316)
at android.database.Contentobserver.onChange(ContentObserver.java:145)
解決方法:修復空指針
DEBUG : pid: 296, tid: 1721, name: Binder:296_4 >>> /system/bin/surfaceflinger <<<
DEBUG : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr ------
DEBUG : Abort message: 'status.cpp:149] Failed HIDL return status not checked: Status(EXTRANSACTIONFAILED):
DEBUG : r0 00000000 rl 000006b9
DEBUG : C4 00000128 r5 000006b9
r2 00000006 r3 a5c5d620
r6 a235d60c r7 0000010c
DEAD_OB3ECT:
DEBUG : r8 00000019 r9 0000015d
DEBUG : ip a6ablbec sp a235d5f8
rlO a568f090 rll a620dce9
Ir a5be901d pc a5be0da2
/system/lib/libc.so (abort+62)
/system/lib/libbase.so (android::base::DefaultAborter(char const )+6)
backtrace:
/system/lib/libsurfaceflinger.so
/system/lib/libsurfaceflinger.so
/system/lib/libsurfaceflinger.so
/system/lib/libsurfaceflinger.so
/system/lib/libbase.so (android::base::LogMessage::~LogMessage()+502)
/system/lib/libhidlbase.so (android::hardware::details::return_status::~return_status()+184)
(android::Hwc2::impl::Composer::getActiveConfig(unsigned long long, unsigned int )+56)
(HWC2::Display::getActiveConfig(std::_1::shared_ptr<HWC2::Display::Config const>*) const+38)
(android::HWComposer::getActiveConfig(int) const+64)
(android::SurfaceFlinger::resyncToHardwareVsync(bool)+64)
可以根據backtrace來進行定位異常崩潰的地方。Android P上, backtrace使用Java上下文來顯示,省去使用addr2line來轉換的一個過程,方便調試分析問題。但是實際場景中,
有些native進程崩潰只有pc地址,而無函數信息,或者需要定位到具體的某個文件某個函數,則可藉助堆棧分析工具addr2line。
addr2line:根據堆棧定位具體函數和文件
addr2line -e libsurfaceflinger.so -f 00071a09
addr2line -e libsurfaceflinger.so -f 00071a09
_
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:1229
需注意兩點:
1、需用帶debug信息的LINK目錄裡面的so庫,機頂盒上的so庫是無法定位的:
out/target/proct/xx/obj/SHARED_LIBRARIES/libsurfaceflinger_intermediates/LINKED/libsurfaceflinger.so
或者:out/target/proct/xx/symbols/system/lib/libsurfaceflinger.so
2、定位的文件,必現和機器上出現問題的版本一致,否則定位不準確
debuggerd:列印當前進程實時堆棧:debuggerd –b pid
主要可以分為以下3類
1)Data abort
Unable to handle kernel NULL pointer dereference at virtual address...
Unable to handle kernel paging request at virtual address...
Unhandled fault...at...
Unhandled prefetch abort...at...
2)BUG/BUG_ON
Oops - BUG...
例如:
Out of memory and no killable processes...
rbus timeout...
...
PS:WARN_ON只mp stacks,kernel還是正常
3)bad mode
Oops - bad mode...
日誌列印:
〃錯誤類型原因
[214.962667] 08:14:19.315 (2)-0488 Unable to handle kernel paging request at virtual address 6b6b6cl7
[214.973889] 08:14:19.326 (2)-0488 addr:6b6b6c17 pgd = d0824000
[214.980132] [6b6b6c17J •pgd=O000eO0e
〃Oopsttl誤碼序號
[214.983865] 08:14:19.336 (2)-0488 Internal error: Oops: 805 [#1] PREEMPT SMP ARM
[214.9914S3] Moles linked in: 8192eu ufsd(PO) jnl(O) fusion(O)
〃發生也錯誤的CPU序號
(215.001878] 08:14:19.354 (2)-0488 CPU: 2 PID: 488 Comm: system_server Tainted: P 4.4.3+ #113
(2)-0488 Hardware name: rtd284x
[215.011865] 08:14:19.364
〃當前PC指針 98:14:19.377 (2)-0488 PC is at mutex_unlo<k+0xc/0x38
(21S.024846] 08:14:19.383 (2)-0488 LR is at storage_pm_event+0xb4/0xe8
(21S.031026]
//Registers 08:14:19.390 (2)-0488 :[<ceb78ffc>] Ir : [<C0542034>] psr: 200f0013
I 215.037644] sp : ccf79e38 ip : eceoeeee fp : 9b34648c
I 215.037644]
08:14:19.404 (2)-0488 rlO: 00000080 r9 :Cl8b3864 r8 : oeeeeeoe
215.051370]
215.058692] 08:14:19.411 (2)-0488 P7 : C1293a98 P6 :C1293940 r5 : C1293940 r4 :C1293a80
21S.067345]
[ 215.076014] 08:14:19.420 (2)-0488 r3 : 00000033 r2 :00000000 ri : 000^000 re :6b6b6c07
[ 215.085307]
08:14:19.428 (2)-0488 Flags: nzCv IRQs on FIQs on Mode SVC 32 ISA ARM Segment user
08:14:19.438 (2)-0488 Control: 10c5383d Table: 1082406a DAC: 00000055
//Process.不 ,定是該process的錯誤,只是發生錯誤時,剛好在運行該process
[215.093168]
//Stacks 08:14:19.446 (2)-0488 Process syste«i_server (pid: 488, stack limit = 0xccf78218)
(21S.101827] 08:14:19.454 (2)-0488 Stack: 0xccf79e38 (Oxccf79d7。 to 0xccf7a08Q) - par(0xcf796d4)
---[ end trace 45d55384id6a0974 ]--- Kernel panic not syncing: Fatal exception
[217.359794] 08:14:21.712 (0)-0488
解決方案: kernel異常一般找晶元原廠協助分析。
系統卡頓時,一般先分三步走:
1、查看當前系統的CPU,IO等參數,輸入top、iotop命令: (如:iotop -s io -m 9)
如果有異常飆高的進程,kill掉後會發現系統恢復正常。
之前項目上遇到過某些U盤IO性能比較差,媒體中心又在後台掃描媒體問題,導致系統各種卡頓,io wait時間比較長。
2、系統進程卡住,觸發Watchdog:ps –A |grep system_server,一般而言,system_server正常的進程號是200多,如果發現進程號變成幾千,則可能出現重啟,結合tombstone和 /data/anr下的trace文件分析重啟原因
3、當前應用出現卡頓,造成ANR。輸入logcat | grep ANR,如果有ANR列印,再去/data/anr下面查看相應進程的traces文件
有時在應用裡面操作卡頓,按鍵響應延遲,但是卻沒有生成ANR,此時如果退出該應用(如果無法退出,在抓取足夠信息的情況下,可以串口直接kill掉卡頓的應用),則一切正常,可能是應用自身實現問題,或者調用了其它介面導致(例如曾遇到應用調用了中間件、mediaplayer某些介面導致操作嚴重卡頓,按鍵響應延遲),這種情況則需應用和相應介面的實現者去排查。
系統完全卡死,一般分三種情況
1,串口無響應,大概率kernel panic,
2,串口日誌狂輸出,把系統堵塞, 優化日誌輸出,關注關閉後壓測。
3,Input系統完全堵塞,導致任何輸入都無響應。
㈡ android 怎麼列印函數堆棧 java
C++也是支持異常處理的,異常處理庫中,已經包含了獲取backtrace的介面,Android也是利用這個介面來列印堆棧信息的。在Android的C++中,已經集成了一個工具類CallStack,在libutils.so中。
使用方法:
[cpp]viewplain
#include<utils/CallStack.h>
...
CallStackstack;
stack.update();
stack.mp();
使用方式比較簡單。目前Andoid4.2版本已經將相關信息解析的很到位,符號表查找,demangle,偏移位置校正都做好了。
㈢ android 怎麼編譯so文件
android NDK編譯多個so文件
android編譯系統的makefile文件Android.mk寫法如下
(1)Android.mk文件首先需要指定LOCAL_PATH變數,用於查找源文件。由於一般情況下
Android.mk和需要編譯的源文件在同一目錄下,所以定義成如下形式:
LOCAL_PATH:=$(call my-dir)
上面的語句的意思是將LOCAL_PATH變數定義成本文件所在目錄路徑。
(2)Android.mk中可以定義多個編譯模塊,每個編譯模塊都是以include $(CLEAR_VARS)開始
以include $(BUILD_XXX)結束。
include $(CLEAR_VARS)
CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE為你清除除LOCAL_PATH以外的所有LOCAL_XXX變數,
如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_SHARED_LIBRARIES,LOCAL_STATIC_LIBRARIES等。
include $(BUILD_STATIC_LIBRARY)表示編譯成靜態庫
include $(BUILD_SHARED_LIBRARY)表示編譯成動態庫。
include $(BUILD_EXECUTABLE)表示編譯成可執行程序
(3)舉例如下(frameworks/base/libs/audioflinger/Android.mk):
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) 模塊一
ifeq ($(AUDIO_POLICY_TEST),true)
ENABLE_AUDIO_DUMP := true
endif
LOCAL_SRC_FILES:= \
AudioHardwareGeneric.cpp \
AudioHardwareStub.cpp \
AudioHardwareInterface.cpp
ifeq ($(ENABLE_AUDIO_DUMP),true)
LOCAL_SRC_FILES += AudioDumpInterface.cpp
LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
endif
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libmedia \
libhardware_legacy
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_CFLAGS += -DGENERIC_AUDIO
endif
LOCAL_MODULE:= libaudiointerface
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_SRC_FILES += A2dpAudioInterface.cpp
LOCAL_SHARED_LIBRARIES += liba2dp
LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
LOCAL_C_INCLUDES += $(call include-path-for, bluez)
endif
include $(BUILD_STATIC_LIBRARY) 模塊一編譯成靜態庫
include $(CLEAR_VARS) 模塊二
LOCAL_SRC_FILES:= \
AudioPolicyManagerBase.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libmedia
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_LDLIBS += -ldl
else
LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudiopolicybase
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_CFLAGS += -DWITH_A2DP
endif
ifeq ($(AUDIO_POLICY_TEST),true)
LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif
include $(BUILD_STATIC_LIBRARY) 模塊二編譯成靜態庫
include $(CLEAR_VARS) 模塊三
LOCAL_SRC_FILES:= \
AudioFlinger.cpp \
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
AudioResamplerSinc.cpp.arm \
AudioResamplerCubic.cpp.arm \
AudioPolicyService.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libmedia \
libhardware_legacy
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
LOCAL_CFLAGS += -DGENERIC_AUDIO
else
LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
endif
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_LDLIBS += -ldl
else
LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudioflinger
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
LOCAL_SHARED_LIBRARIES += liba2dp
endif
ifeq ($(AUDIO_POLICY_TEST),true)
LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif
ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt -lpthread
endif
endif
ifeq ($(BOARD_USE_LVMX),true)
LOCAL_CFLAGS += -DLVMX
LOCAL_C_INCLUDES += vendor/nxp
LOCAL_STATIC_LIBRARIES += liblifevibes
LOCAL_SHARED_LIBRARIES += liblvmxservice
# LOCAL_SHARED_LIBRARIES += liblvmxipc
endif
include $(BUILD_SHARED_LIBRARY) 模塊三編譯成動態庫
(4)編譯一個應用程序(APK)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory-->直譯(建立在java子目錄中的所有Java文件)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build-->直譯(創建APK的名稱)
LOCAL_PACKAGE_NAME := LocalPackage
# Tell it to build an APK-->直譯(告訴它來建立一個APK)
include $(BUILD_PACKAGE)
(5)編譯一個依賴於靜態Java庫(static.jar)的應用程序
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# List of static libraries to include in the package
LOCAL_STATIC_JAVA_LIBRARIES := static-library
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
# Tell it to build an APK
include $(BUILD_PACKAGE)
(6)編譯一個需要用平台的key簽名的應用程序
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
LOCAL_CERTIFICATE := platform
# Tell it to build an APK
include $(BUILD_PACKAGE)
(7)編譯一個需要用特定key前面的應用程序
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
LOCAL_CERTIFICATE := vendor/example/certs/app
# Tell it to build an APK
include $(BUILD_PACKAGE)
(8)添加一個預編譯應用程序
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Mole name should match apk name to be installed.
LOCAL_MODULE := LocalMoleName
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
include $(BUILD_PREBUILT)
(9)添加一個靜態JAVA庫
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Any libraries that this library depends on
LOCAL_JAVA_LIBRARIES := android.test.runner
# The name of the jar file to create
LOCAL_MODULE := sample
# Build a static jar file.
include $(BUILD_STATIC_JAVA_LIBRARY)
(10)Android.mk的編譯模塊中間可以定義相關的編譯內容,也就是指定相關的變數如下:
LOCAL_AAPT_FLAGS
LOCAL_ACP_UNAVAILABLE
LOCAL_ADDITIONAL_JAVA_DIR
LOCAL_AIDL_INCLUDES
LOCAL_ALLOW_UNDEFINED_SYMBOLS
LOCAL_ARM_MODE
LOCAL_ASFLAGS
LOCAL_ASSET_DIR
LOCAL_ASSET_FILES 在Android.mk文件中編譯應用程序(BUILD_PACKAGE)時設置此變數,表示資源文件,
通常會定義成LOCAL_ASSET_FILES += $(call find-subdir-assets)
LOCAL_BUILT_MODULE_STEM
LOCAL_C_INCLUDES 額外的C/C++編譯頭文件路徑,用LOCAL_PATH表示本文件所在目錄
舉例如下:
LOCAL_C_INCLUDES += extlibs/zlib-1.2.3
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
LOCAL_CC 指定C編譯器
LOCAL_CERTIFICATE 簽名認證
LOCAL_CFLAGS 為C/C++編譯器定義額外的標志(如宏定義),舉例:LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1
LOCAL_CLASSPATH
LOCAL_COMPRESS_MODULE_SYMBOLS
LOCAL_COPY_HEADERS install應用程序時需要復制的頭文件,必須同時定義LOCAL_COPY_HEADERS_TO
LOCAL_COPY_HEADERS_TO install應用程序時復制頭文件的目的路徑
LOCAL_CPP_EXTENSION 如果你的C++文件不是以cpp為文件後綴,你可以通過LOCAL_CPP_EXTENSION指定C++文件後綴名
如:LOCAL_CPP_EXTENSION := .cc
注意統一模塊中C++文件後綴必須保持一致。
LOCAL_CPPFLAGS 傳遞額外的標志給C++編譯器,如:LOCAL_CPPFLAGS += -ffriend-injection
LOCAL_CXX 指定C++編譯器
LOCAL_DX_FLAGS
LOCAL_EXPORT_PACKAGE_RESOURCES
LOCAL_FORCE_STATIC_EXECUTABLE 如果編譯的可執行程序要進行靜態鏈接(執行時不依賴於任何動態庫),則設置LOCAL_FORCE_STATIC_EXECUTABLE:=true
目前只有libc有靜態庫形式,這個只有文件系統中/sbin目錄下的應用程序會用到,這個目錄下的應用程序在運行時通常
文件系統的其它部分還沒有載入,所以必須進行靜態鏈接。
LOCAL_GENERATED_SOURCES
LOCAL_INSTRUMENTATION_FOR
LOCAL_INSTRUMENTATION_FOR_PACKAGE_NAME
LOCAL_INTERMEDIATE_SOURCES
LOCAL_INTERMEDIATE_TARGETS
LOCAL_IS_HOST_MODULE
LOCAL_JAR_MANIFEST
LOCAL_JARJAR_RULES
LOCAL_JAVA_LIBRARIES 編譯java應用程序和庫的時候指定包含的java類庫,目前有core和framework兩種
多數情況下定義成:LOCAL_JAVA_LIBRARIES := core framework
注意LOCAL_JAVA_LIBRARIES不是必須的,而且編譯APK時不允許定義(系統會自動添加)
LOCAL_JAVA_RESOURCE_DIRS
LOCAL_JAVA_RESOURCE_FILES
LOCAL_JNI_SHARED_LIBRARIES
LOCAL_LDFLAGS 傳遞額外的參數給連接器(務必注意參數的順序)
LOCAL_LDLIBS 為可執行程序或者庫的編譯指定額外的庫,指定庫以"-lxxx"格式,舉例:
LOCAL_LDLIBS += -lcurses -lpthread
LOCAL_LDLIBS += -Wl,-z,origin
LOCAL_MODULE 生成的模塊的名稱(注意應用程序名稱用LOCAL_PACKAGE_NAME而不是LOCAL_MODULE)
LOCAL_MODULE_PATH 生成模塊的路徑
LOCAL_MODULE_STEM
LOCAL_MODULE_TAGS 生成模塊的標記
LOCAL_NO_DEFAULT_COMPILER_FLAGS
LOCAL_NO_EMMA_COMPILE
LOCAL_NO_EMMA_INSTRUMENT
LOCAL_NO_STANDARD_LIBRARIES
LOCAL_OVERRIDES_PACKAGES
LOCAL_PACKAGE_NAME APK應用程序的名稱
LOCAL_POST_PROCESS_COMMAND
LOCAL_PREBUILT_EXECUTABLES 預編譯including $(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用,指定需要復制的可執行文件
LOCAL_PREBUILT_JAVA_LIBRARIES
LOCAL_PREBUILT_LIBS 預編譯including $(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用, 指定需要復制的庫.
LOCAL_PREBUILT_OBJ_FILES
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES
LOCAL_PRELINK_MODULE 是否需要預連接處理(默認需要,用來做動態庫優化)
LOCAL_REQUIRED_MODULES 指定模塊運行所依賴的模塊(模塊安裝時將會同步安裝它所依賴的模塊)
LOCAL_RESOURCE_DIR
LOCAL_SDK_VERSION
LOCAL_SHARED_LIBRARIES 可鏈接動態庫
LOCAL_SRC_FILES 編譯源文件
LOCAL_STATIC_JAVA_LIBRARIES
LOCAL_STATIC_LIBRARIES 可鏈接靜態庫
LOCAL_UNINSTALLABLE_MODULE
LOCAL_UNSTRIPPED_PATH
LOCAL_WHOLE_STATIC_LIBRARIES 指定模塊所需要載入的完整靜態庫(這些精通庫在鏈接是不允許鏈接器刪除其中無用的代碼)
LOCAL_YACCFLAGS
OVERRIDE_BUILT_MODULE_PATH
㈣ android的系統結構
Android 是運行於Linux kernel之上,但並不是GNU/Linux。因為在一般GNU/Linux 里支持的功能,Android 大都沒有支持,包括Cairo、X11、Alsa、FFmpeg、GTK、Pango及Glibc等都被移除掉了。Android又以Bionic 取代Glibc、以謹段Skia 取代Cairo、再以opencore取代FFmpeg等等。Android 為了達到商業應用,必須移除被GNU GPL授權證所約束的部份,例如Android將驅動程序移到 Userspace,使得Linux driver 與 Linux kernel徹底分開。Bionic/Libc/Kernel/ 並非標準的Kernel header files。Android 的 Kernel header 是利用工具由 Linux Kernel header 所產生的,這樣做是為了保留常數、數據結構與宏。
Android 的 Linux kernel控制包括安全(Security),存儲器管理(Memory Management),程序管理(Process Management),網路堆棧(Network Stack),驅動程序模型(Driver Model)等。下載Android源碼之前,先要安裝其構建工具 Repo來初始化源碼。Repo 是 Android 用來輔助Git工作的一個工具。 APK是安卓應用的後綴,是AndroidPackage的縮寫,即Android安裝包祥陵譽(apk)。APK是類似Symbian Sis或Sisx的文件格式。通過將APK文件直接傳到Android模擬器或Android手機中執行即可安裝。apk文件和sis一樣,把android sdk編譯的工程打包成一個安裝程序文件,格式為apk。 APK文件其實是zip格式,但後綴名被修改為apk,通過UnZip解壓後,可以看到Dex文件,Dex是Dalvik VM executes的全稱,即Android Dalvik執行程序,並非Java ME的位元組碼而是Dalvik位元組碼。
APK文件結構
一個APK文件結構為:
1. META-INF (註:Jar文件中常可以看到);
2. res (註:存放資源文件的目錄) ;
3. AndroidManifest.xml (註:程序全局配置文件) ;
4. classes.dex (註:Dalvik位元組碼);
5. resources.arsc (註:編譯後的二進制資源文件)。
總結下我們發現Android在運行一個程序時首先需要UnZip,然後類似Symbian那樣直接執行安裝,和Windows Mobile中的PE文件有區別,這樣做對於程序的保密性和可靠性不是很高,通過dexmp命令可以反編譯,但這樣做符合發展規律,微軟的 Windows Gadgets或者說WPF也採用了這種構架方式。
在Android平台中dalvik vm的執行文件被打包為apk格式,最終運行時載入器會解壓然後獲取編譯後androidmanifest.xml文件中的permission分支相關的安全訪問,但仍然存在很多安全限制,如果你將apk文件傳到/system/app文件夾下會發現執行是不受限制的。
最終我們平時安裝的文件可能不是這個文件夾,而在android rom中系統的apk文件默認會放入這個文件夾,它們擁有著root許可權。 Android 的HAL(硬體抽像層)是能以封閉源碼形式提供硬體驅動模塊。HAL 的目的是為了把 Android framework 與 Linux kernel 隔開,讓 Android 不至過度依賴 Linux kernel,以達成 Kernel independent 的概念汪塌,也讓 Android framework 的開發能在不考量驅動程序實現的前提下進行發展。
HAL stub 是一種代理人(Proxy)的概念,Stub 是以 *.so 檔的形式存在。Stub 向 HAL「提供」操作函數(Operations),並由 Android runtime 向 HAL 取得 Stub 的Operations,再 Callback 這些操作函數。HAL 里包含了許多的 Stub(代理人)。Runtime 只要說明「類型」,即 Mole ID,就可以取得操作函數。 操作系統與應用程序的溝通橋梁,應用分為兩層:函數層(Library)和虛擬機(Virtual Machine)。 Bionic是 Android 改良libc的版本。Android 同時包含了Webkit,所謂的Webkit 就是Apple Safari 瀏覽器背後的引擎。Surface flinger 是就2D或3D的內容顯示到屏幕上。Android使用工具鏈(Toolchain)為Google自製的Bionic Libc。
Android採用OpenCORE作為基礎多媒體框架。Open CORE可分7大塊:PVPlayer、PVAuthor、Codec、PacketVideo Multimedia Framework(PVMF)、Operating System Compatibility Library(OSCL)、Common、OpenMAX。
Android 使用skia 為核心圖形引擎,搭配OpenGL/ES。skia與Linux Cairo功能相當,但相較於Linux Cairo, skia 功能還只是雛形的。2005年Skia公司被Google收購,2007年初,Skia GL源碼被公開,Skia 也是Google Chrome 的圖形引擎。
Android的多媒體資料庫採用SQLite資料庫系統。資料庫又分為共用資料庫及私用資料庫。用戶可通過ContentResolver類(Column)取得共用資料庫。
Android的中間層多以Java 實現,並且採用特殊的Dalvik 虛擬機(Dalvik Virtual Machine)。Dalvik虛擬機是一種「暫存器型態」(Register Based)的Java虛擬機,變數皆存放於暫存器中,虛擬機的指令相對減少。
Dalvik虛擬機可以有多個實例(Instance), 每個Android應用程序都用一個自屬的Dalvik虛擬機來運行,讓系統在運行程序時可達到優化。Dalvik 虛擬機並非運行Java位元組碼(Bytecode),而是運行一種稱為.dex格式的文件。 Android本身是一個許可權分立的操作系統。在這類操作系統中,每個應用都以唯一的一個系統識別身份運行(Linux用戶ID與群組ID)。系統的各部分也分別使用各自獨立的識別方式。Linux就是這樣將應用與應用,應用與系統隔離開。
系統更多的安全功能通過許可權機制提供。許可權可以限制某個特定進程的特定操作,也可以限制每個URI許可權對特定數據段的訪問。
Android安全架構的核心設計思想是,在默認設置下,所有應用都沒有許可權對其他應用、系統或用戶進行較大影響的操作。這其中包括讀寫用戶隱私數據(聯系人或電子郵件),讀寫其他應用文件,訪問網路或阻止設備待機等。
安裝應用時,在檢查程序簽名提及的許可權,且經過用戶確認後,軟體包安裝器會給予應用許可權。從用戶角度看,一款Android應用通常會要求如下的許可權:
撥打電話、發送簡訊或彩信、修改/刪除SD卡上的內容、讀取聯系人的信息、讀取日程信的息,寫入日程數據、讀取電話狀態或識別碼、精確的(基於GPS)地理位置、模糊的(基於網路獲取)地理位置、創建藍牙連接、對互聯網的完全訪問、查看網路狀態,查看WiFi狀態、避免手機待機、修改系統全局設置、讀取同步設定、開機自啟動、重啟其他應用、終止運行中的應用、設定偏好應用、震動控制、拍攝圖片等。
一款應用應該根據自身提供的功能,要求合理的許可權。用戶也可以分析一款應用所需許可權,從而簡單判定這款應用是否安全。如一款應用是不帶廣告的單機版,也沒有任何附加的內容需要下載,那麼它要求訪問網路的許可權就比較可疑。
㈤ Android APP加密方法都有哪些
1 偽加密是Android4.2.x系統發布前的Android加密方式之一,通過java代碼對APK(壓縮文件)進行偽加密,其修改原理是修改連續4位位元組標記為」P K 01 02」的後第5位位元組,奇數表示不加密偶數表示加密。
2 混淆保護
把原來有具體含義的類名,變數名,方法名,修改成讓人看不懂的名字,例如方法名getUserName編程了方法名。
混淆保護只是增加了代碼閱讀難度,對於破解基本上是沒有實質性作用的
運行時驗證,主要是指在代碼啟動的時候本地獲取簽名信息然後對簽名信息進行檢驗來判斷自己的應用是否是正版,如果簽名信息不是正版則提示盜版或者直接崩潰。當然你可以把必要的數據放在伺服器端。Android APP加密方法都有哪些?破解:找到smali文件中,判斷是否相等的部分。改為常量true,即失效。
總之,反編譯一些apk之後,只要是java代碼寫的總會有smil文件。對於smil文件,如果耐心讀的話,還是可以查看到一些關鍵代碼的。
相較於應用來說,游戲apk因為採用cocos2d-x或者 unity3D,採用的是c++和c# 編寫的跨平台程序,在apk採用JNI的方式。所以沒有smali,可以防止靜態被破解apk包。
當然游戲包apk在運行的時候,會把.*so載入到內存中。動態也是可以在內存中抓取相應的數據。只不過NDK相對於smali破解來說,根部不是一個層級的關系。
3 使用第三方Android加密平台
㈥ 安卓app360加固怎麼反編譯
1 對比
上傳demo進行加固,解包後對比下原包和加固包,發現加固包在assets文件夾下多了libjiagu.so,libjiagu_x86,lib文件夾下多了libjiagu_art.so,同時修改了dex文件和AndroidManifest文件
打開manifest文件,看到xxx加固對Application標簽做了修改,添加了殼入口,也就是我們反編譯後看到的StubApplication.smali這個文件。
相比於之前版本的加固,自從1.x.x.x加固版本之後,多了幾次反調試,使得動態難度稍微增大了一些,不過針對脫殼機脫殼,再多了反調試也是無用。或者通過修改系統源碼,也能達到消除反調試的作用。
2 動態調試
(1)把app安裝到手機,以調試模式打開app
(2)以shell模式root許可權打開IDA的android_server監聽
(3)tcp轉發
(4)打開IDA,修改配置為在進程開始時下斷
(5)搜索到進程後jdwp轉發,pid值即為我們進程號,並在命令行下附加。
成功附加後,可以下段了,打開Debugger Option
我們選擇在線程開始和庫載入時下斷,修改成功後,jdb附加,點擊運行
程序會斷在elf頭處,按下G鍵,搜索mmap,在mmap函數的段首和斷尾下段
F9運行,來到斷尾時F8單步,
來到此處時,在 BLunk_5C999C2C下斷,F9一下,F7跟進去
跟進去今後在BLX LR處進行下斷,此處就是進行反調試的地方,原理依然是獲取TracePid的值判斷當前是不是處於調試狀態,建議第一次調試的人在fgets和fopen處下斷,再f7跟進此調用就可以看到TracePid的值了。
跟進去之後,我們直接把方法移到最下方,就可以看到kill符號了,這就是殺進程的地方,如果當前處於調試狀態,則直接結束進程。
我們在此函數的所有cmpR0,#0處下斷,F9一下後即斷在斷點處,觀察寄存器窗口的R0值,實質就是當前的TracePid的16進制的值
不確定的可以使用cat /proc/pid/status進行對比一下,我們直接把R0置0,右鍵選擇Zero Value即可清0,繼續F9
我們看到程序又來到了mmap處,繼續f9
當繼續斷在調用反調試功能的方法時,繼續F7跟進,依然在所有的cmp R0,#0處下斷,斷下後把R0清0後繼續F9運行
目前的規律是,調用BLXLR的第一次,第二次和第四次是進行反調試判斷的,第三次並不影響,可以直接f9跳過去,三次反調試搞定後,就可以愉快的F9運行並觀察堆棧窗口了
當看到出現如下所示時:
說明殼已經開始解密並釋放dex文件了,我們直接F8單步十幾步,最後F9一下就可以看到我們需要的dex頭了
直接腳本mp出來即可,最後把libjiagu的所有文件刪除,並修復下Application標,如果存在則修復,不存在刪除即可
㈦ android怎樣破解已使用加殼技術的APP
破解加了dex殼的app,關鍵是要獲得解密後的源dex,現在Android加殼技術大多都是通過DexClassLoader或者隱藏的函數openDexFile來將源dex載入進來,然後動態替換Application來啟動源程序,跟Windows上傳統的PE文件加殼有一定區別。
要破解傳統的殼,需要跟蹤控制流找到OEP,然後把源程序從內存中mp下來,重建輸入表,最困難的就是要跟著外殼的控制流走,安全工程師為了加大破解難度,使用了很多技術來讓破解者走得更艱難。安全工程師與破解者對抗的關鍵點就在尋找OEP的困難性上。
在Android平台上,正因為新興的dex加殼技術不成熟,導致有些另類的脫殼方法可以繞過分析演算法,直接將源程序mp下來。
舉個例子,安卓在4.0版本以後提供openDexFile這個函數來從內存中載入dex,所需要提供的參數是源dex在內存中的地址,所以只要對這個函數下斷,然後從寄存器里找到內存地址,就能將解密後的源dex從內存中mp下來,直接對其反編譯就能獲得源代碼了。
更進一步,關於openDexFile這個函數,其實它與libdvm.so這個庫有密不可分的關系,這個庫里提供大量操作dex文件的函數,如果對這個庫里的相關函數下斷,然後從內存中暴力mp一大塊內存區域,經常能直接將內存中的源dex給抓下來。