概述
Framework开发是一项非常繁琐复杂的工作,需要阅读大量的源代码,分析及其多的LOG信息来定位错误位置。这个时候如果使用一些工具或者知道如何定位重要LOG信息,就可以使一些复杂的工作变的简单很多,使我们分析问题的效率变得更快,不再为阅读大量的源代码而感到一筹莫展。本文将针对一些场景讲解如何分析系统LOG信息,如何添加LOG定位错误信息,以及常用工具以及使用方法。
常用工具
HierarchyViewer
HierarchyViewer是随Android SDK发布的工具,位置在sdk的tools文件夹下,名为hierarchyviewer。它是Android自带的非常有用而且使用简单的工具,能够让我们从可视化的角度直观地获得UI布局设计结构和各种属性的信息,帮助我们优化布局设计。打开HierarchyViewer后我们可以看到当前view的布局,如下图所示。
DDMS
DDMS 的全称是Dalvik Debug Monitor Service,是 Android 开发环境中的Dalvik虚拟机调试监控服务。它为我们提供例如:为测试设备截屏,针对特定的进程查看正在运行的线程以及堆信息、Logcat、广播状态信息、模拟电话呼叫、接收SMS、虚拟地理坐标等等。DDMS打开界面如下:
左侧的Devices一栏会列出已连接的设备,点击设备名称左侧三角符号图标会列出该设备运行中的进程的app包名。
模拟按键
使用命令adb shell input keyevent + 对应的键值,可以模拟对应的操作。手机系统中主要的键值如下:
- /** Key code constant: Home key.
- * This key is handled by the framework and is never delivered to applications. */
- public static final int KEYCODE_HOME = 3; //Home键
- /** Key code constant: Back key. */
- public static final int KEYCODE_BACK = 4; //Back键
- /** Key code constant: Call key. */
- public static final int KEYCODE_CALL = 5; //打电话
- /** Key code constant: End Call key. */
- public static final int KEYCODE_ENDCALL = 6; //挂断电话
- /** Key code constant: Volume Up key.
- * Adjusts the speaker volume up. */
- public static final int KEYCODE_VOLUME_UP = 24; //调大声音
- /** Key code constant: Volume Down key.
- * Adjusts the speaker volume down. */
- public static final int KEYCODE_VOLUME_DOWN = 25; //调小声音
- /** Key code constant: Power key. */
- public static final int KEYCODE_POWER = 26; //电源键
- /** Key code constant: Camera key.
- * Used to launch a camera application or take pictures. */
- public static final int KEYCODE_CAMERA = 27; //相机按键
- /** Key code constant: Clear key. */
- public static final int KEYCODE_CLEAR = 28; //清理
- /** Key code constant: Space key. */
- public static final int KEYCODE_SPACE = 62; //空格键
- /** Key code constant: Backspace key.
- * Deletes characters before the insertion point, unlike {@link #KEYCODE_FORWARD_DEL}. */
- public static final int KEYCODE_DEL = 67; //删除键
- /** Key code constant: Menu key. */
- public static final int KEYCODE_MENU = 82; //菜单键
当我们要模拟power键亮灭屏事件就可以执行下面命令:
- adb shell input keyevent 26
模拟别的按键事件同理。
而adb shell getevent / adb shell sendevent是发送对应的事件,包括触屏,按键等事件。
am命令
有时候我们在调试系统时可以在终端使用am命令来发送广播,打开Activity,启动Service等操作,十分方便。am的详细操作如下,我们可以通过adb shell am + 对应命令,就可操作。
- usage: am [subcommand] [options]
- usage: am start [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]
- [--sampling INTERVAL] [-R COUNT] [-S]
- [--track-allocation] [--user <USER_ID> | current] <INTENT> //可以通过该命令启动对应Activity
- am startservice [--user <USER_ID> | current] <INTENT> //启动服务
- am stopservice [--user <USER_ID> | current] <INTENT> //停止服务
- am force-stop [--user <USER_ID> | all | current] <PACKAGE> //通过包名强制停止应用
- am kill [--user <USER_ID> | all | current] <PACKAGE> //根据进程号杀死进程
- am kill-all //杀掉所有后台进程
- am broadcast [--user <USER_ID> | all | current] <INTENT> //发送广播
- am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]
- [--user <USER_ID> | current]
- [--no-window-animation] [--abi <ABI>] <COMPONENT>
- am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE> //抓取traceview
- am profile stop [--user <USER_ID> current] [<PROCESS>] //停止抓取traceview
- am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>
- am set-debug-app [-w] [--persistent] <PACKAGE>
- am clear-debug-app
- am set-watch-heap <PROCESS> <MEM-LIMIT>
- am clear-watch-heap
- am bug-report [--progress]
- am monitor [--gdb <port>]
- am hang [--allow-restart]
- am restart //重启应用
- am idle-maintenance
- am screen-compat [on|off] <PACKAGE>
- am package-importance <PACKAGE>
- am to-uri [INTENT]
- am to-intent-uri [INTENT]
- am to-app-uri [INTENT]
- am switch-user <USER_ID>
- am start-user <USER_ID>
- am unlock-user <USER_ID> [TOKEN_HEX]
- am stop-user [-w] [-f] <USER_ID>
- am stack start <DISPLAY_ID> <INTENT>
- am stack movetask <TASK_ID> <STACK_ID> [true|false] //stack相关
- am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]
- am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]
- am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am stack positiontask <TASK_ID> <STACK_ID> <POSITION>
- am stack list //列出系统中的所有stack
- am stack info <STACK_ID> //stack信息
- am stack remove <STACK_ID> //移除stack
- am task lock <TASK_ID>
- am task lock stop
- am task resizeable <TASK_ID> [0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)]
- am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS]
- am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS]
- am get-config
- am suppress-resize-config-changes <true|false>
- am set-inactive [--user <USER_ID>] <PACKAGE> true|false
- am get-inactive [--user <USER_ID>] <PACKAGE>
- am send-trim-memory [--user <USER_ID>] <PROCESS>
- [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]
- am get-current-user
- am start: start an Activity. Options are: //启动Activity详细使用方法
- -D: enable debugging
- -N: enable native debugging
- -W: wait for launch to complete
- --start-profiler <FILE>: start profiler and send results to <FILE>
- --sampling INTERVAL: use sample profiling with INTERVAL microseconds
- between samples (use with --start-profiler)
- -P <FILE>: like above, but profiling stops when app goes idle
- -R: repeat the activity launch <COUNT> times. Prior to each repeat,
- the top activity will be finished.
- -S: force stop the target app before starting the activity
- --track-allocation: enable tracking of object allocations
- --user <USER_ID> | current: Specify which user to run as; if not
- specified then run as the current user.
- --stack <STACK_ID>: Specify into which stack should the activity be put.
- am startservice: start a Service. Options are:
- --user <USER_ID> | current: Specify which user to run as; if not
- specified then run as the current user.
- am stopservice: stop a Service. Options are:
- --user <USER_ID> | current: Specify which user to run as; if not
- specified then run as the current user.
- am force-stop: force stop everything associated with <PACKAGE>.
- --user <USER_ID> | all | current: Specify user to force stop;
- all users if not specified.
- am kill: Kill all processes associated with <PACKAGE>. Only kills.
- processes that are safe to kill -- that is, will not impact the user
- experience.
- --user <USER_ID> | all | current: Specify user whose processes to kill;
- all users if not specified.
- am kill-all: Kill all background processes.
- am broadcast: send a broadcast Intent. Options are:
- --user <USER_ID> | all | current: Specify which user to send to; if not
- specified then send to all users.
- --receiver-permission <PERMISSION>: Require receiver to hold permission.
- am instrument: start an Instrumentation. Typically this target <COMPONENT>
- is the form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there
- is only one instrumentation. Options are:
- -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with
- [-e perf true] to generate raw output for performance measurements.
- -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a
- common form is [-e <testrunner_flag> <value>[,<value>...]].
- -p <FILE>: write profiling data to <FILE>
- -w: wait for instrumentation to finish before returning. Required for
- test runners.
- --user <USER_ID> | current: Specify user instrumentation runs in;
- current user if not specified.
- --no-window-animation: turn off window animations while running.
- --abi <ABI>: Launch the instrumented process with the selected ABI.
- This assumes that the process supports the selected ABI.
- am trace-ipc: Trace IPC transactions.
- start: start tracing IPC transactions.
- stop: stop tracing IPC transactions and dump the results to file.
- --dump-file <FILE>: Specify the file the trace should be dumped to.
- am profile: start and stop profiler on a process. The given <PROCESS> argument
- may be either a process name or pid. Options are:
- --user <USER_ID> | current: When supplying a process name,
- specify user of process to profile; uses current user if not specified.
- am dumpheap: dump the heap of a process. The given <PROCESS> argument may
- be either a process name or pid. Options are:
- -n: dump native heap instead of managed heap
- --user <USER_ID> | current: When supplying a process name,
- specify user of process to dump; uses current user if not specified.
- am set-debug-app: set application <PACKAGE> to debug. Options are:
- -w: wait for debugger when application starts
- --persistent: retain this value
- am clear-debug-app: clear the previously set-debug-app.
- am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or
- above <HEAP-LIMIT> then a heap dump is collected for the user to report
- am clear-watch-heap: clear the previously set-watch-heap.
- am bug-report: request bug report generation; will launch a notification
- when done to select where it should be delivered. Options are:
- --progress: will launch a notification right away to show its progress.
- am monitor: start monitoring for crashes or ANRs.
- --gdb: start gdbserv on the given port at crash/ANR
- am hang: hang the system.
- --allow-restart: allow watchdog to perform normal system restart
- am restart: restart the user-space system.
- am idle-maintenance: perform idle maintenance now.
- am screen-compat: control screen compatibility mode of <PACKAGE>.
- am package-importance: print current importance of <PACKAGE>.
- am to-uri: print the given Intent specification as a URI.
- am to-intent-uri: print the given Intent specification as an intent: URI.
- am to-app-uri: print the given Intent specification as an android-app: URI.
- am switch-user: switch to put USER_ID in the foreground, starting
- execution of that user if it is currently stopped.
- am start-user: start USER_ID in background if it is currently stopped,
- use switch-user if you want to start the user in foreground.
- am stop-user: stop execution of USER_ID, not allowing it to run any
- code until a later explicit start or switch to it.
- -w: wait for stop-user to complete.
- -f: force stop even if there are related users that cannot be stopped.
- am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.
- am stack movetask: move <TASK_ID> from its current stack to the top (true) or bottom (false) of <STACK_ID>.
- am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.
- am stack resize-docked-stack: change docked stack to <LEFT,TOP,RIGHT,BOTTOM>
- and supplying temporary different task bounds indicated by
- <TASK_LEFT,TOP,RIGHT,BOTTOM>
- am stack size-docked-stack-test: test command for sizing docked stack by
- <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom
- applying the optional [DELAY_MS] between each step.
- am stack move-top-activity-to-pinned-stack: moves the top activity from
- <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the
- bounds of the pinned stack.
- am stack positiontask: place <TASK_ID> in <STACK_ID> at <POSITION>
- am stack list: list all of the activity stacks and their sizes.
- am stack info: display the information about activity stack <STACK_ID>.
- am stack remove: remove stack <STACK_ID>.
- am task lock: bring <TASK_ID> to the front and don't allow other tasks to run.
- am task lock stop: end the current task lock.
- am task resizeable: change resizeable mode of <TASK_ID>.
- 0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)
- am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.
- Forces the task to be resizeable and creates a stack if no existing stack
- has the specified bounds.
- am task drag-task-test: test command for dragging/moving <TASK_ID> by
- <STEP_SIZE> increments around the screen applying the optional [DELAY_MS]
- between each step.
- am task size-task-test: test command for sizing <TASK_ID> by <STEP_SIZE> increments within the screen applying the optional [DELAY_MS] between
- each step.
- am get-config: retrieve the configuration and any recent configurations
- of the device.
- am suppress-resize-config-changes: suppresses configuration changes due to
- user resizing an activity/task.
- am set-inactive: sets the inactive state of an app.
- am get-inactive: returns the inactive state of an app.
- am send-trim-memory: send a memory trim event to a <PROCESS>.
- am get-current-user: returns id of the current foreground user.
- <INTENT> specifications include these flags and arguments:
- [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
- [-c <CATEGORY> [-c <CATEGORY>] ...]
- [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
- [--esn <EXTRA_KEY> ...]
- [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
- [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
- [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]
- [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]
- [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]
- [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]
- [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]
- (mutiple extras passed as Integer[])
- [--eial <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]
- (mutiple extras passed as List<Integer>)
- [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
- (mutiple extras passed as Long[])
- [--elal <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
- (mutiple extras passed as List<Long>)
- [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
- (mutiple extras passed as Float[])
- [--efal <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
- (mutiple extras passed as List<Float>)
- [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
- (mutiple extras passed as String[]; to embed a comma into a string,
- escape it using "\,")
- [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
- (mutiple extras passed as List<String>; to embed a comma into a string,
- escape it using "\,")
- [--f <FLAG>]
- [--grant-read-uri-permission] [--grant-write-uri-permission]
- [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]
- [--debug-log-resolution] [--exclude-stopped-packages]
- [--include-stopped-packages]
- [--activity-brought-to-front] [--activity-clear-top]
- [--activity-clear-when-task-reset] [--activity-exclude-from-recents]
- [--activity-launched-from-history] [--activity-multiple-task]
- [--activity-no-animation] [--activity-no-history]
- [--activity-no-user-action] [--activity-previous-is-top]
- [--activity-reorder-to-front] [--activity-reset-task-if-needed]
- [--activity-single-top] [--activity-clear-task]
- [--activity-task-on-home]
- [--receiver-registered-only] [--receiver-replace-pending]
- [--receiver-foreground]
- [--selector]
- [<URI> | <PACKAGE> | <COMPONENT>]
pm命令
当要查询系统中某个应用是否存在,或者存在路径,就可以根据对应的包名来查找对应的apk信息。- usage: pm path [--user USER_ID] PACKAGE
- pm dump PACKAGE //dump某个apk
- pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH] //安装应用
- pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]
- [--install-location 0/1/2]
- [--force-uuid internal|UUID]
- pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]
- pm install-commit SESSION_ID
- pm install-abandon SESSION_ID
- pm uninstall [-k] [--user USER_ID] PACKAGE //卸载应用
- pm set-installer PACKAGE INSTALLER //设置installer
- pm move-package PACKAGE [internal|UUID] //移除package
- pm move-primary-storage [internal|UUID]
- pm clear [--user USER_ID] PACKAGE //清除应用信息
- pm enable [--user USER_ID] PACKAGE_OR_COMPONENT
- pm disable [--user USER_ID] PACKAGE_OR_COMPONENT
- pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT
- pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT
- pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT
- pm hide [--user USER_ID] PACKAGE_OR_COMPONENT
- pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT
- pm grant [--user USER_ID] PACKAGE PERMISSION
- pm revoke [--user USER_ID] PACKAGE PERMISSION
- pm reset-permissions //重置权限
- pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}
- pm get-app-link [--user USER_ID] PACKAGE
- pm set-install-location [0/auto] [1/internal] [2/external] //设置安装路径
- pm get-install-location 获取安装路径
- pm set-permission-enforced PERMISSION [true|false]
- pm trim-caches DESIRED_FREE_SPACE [internal|UUID]
- pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME
- pm remove-user USER_ID
- pm get-max-users
- NOTE: 'pm list' commands have moved! Run 'adb shell cmd package'
- to display the new commands. //使用adb shell pm list packages -f获取系统中所有apk的安装路径
- pm path: print the path to the .apk of the given PACKAGE. //adb shell path +包名,获取apk路径
- pm dump: print system state associated with the given PACKAGE.
- pm install: install a single legacy package
- pm install-create: create an install session
- -l: forward lock application
- -r: replace existing application
- -t: allow test packages
- -i: specify the installer package name
- -s: install application on sdcard
- -f: install application on internal flash
- -d: allow version code downgrade (debuggable packages only)
- -p: partial application install
- -g: grant all runtime permissions
- -S: size in bytes of entire session
- pm install-write: write a package into existing session; path may
- be '-' to read from stdin
- -S: size in bytes of package, required for stdin
- pm install-commit: perform install of fully staged session
- pm install-abandon: abandon session
- pm set-installer: set installer package name
- pm uninstall: removes a package from the system. Options:
- -k: keep the data and cache directories around after package removal.
- pm clear: deletes all data associated with a package.
- pm enable, disable, disable-user, disable-until-used, default-state:
- these commands change the enabled state of a given package or
- component (written as "package/class").
- pm grant, revoke: these commands either grant or revoke permissions
- to apps. The permissions must be declared as used in the app's
- manifest, be runtime permissions (protection level dangerous),
- and the app targeting SDK greater than Lollipop MR1.
- pm reset-permissions: revert all runtime permissions to their default state.
- pm get-install-location: returns the current install location.
- 0 [auto]: Let system decide the best location
- 1 [internal]: Install on internal device storage
- 2 [external]: Install on external media
- pm set-install-location: changes the default install location.
- NOTE: this is only intended for debugging; using this can cause
- applications to break and other undersireable behavior.
- 0 [auto]: Let system decide the best location
- 1 [internal]: Install on internal device storage
- 2 [external]: Install on external media
- pm trim-caches: trim cache files to reach the given free space.
- pm create-user: create a new user with the given USER_NAME,
- printing the new user identifier of the user.
- pm remove-user: remove the user with the given USER_IDENTIFIER,
- deleting all data associated with that user
dumpsys
该命令用于打印出当前系统信息,默认打印出设备中所有service的信息,可以在命令后面加指定的service name。
可以通过adb shell dumpsys + services可以打印出对应系统service的dump信息。可以将某个模块详细信息输出到控制台,可以更加直观的分析。
例如要打印Activity的dump信息:adb shell dumpsys activity
- Currently running services:
- AtCmdFwd
- DockObserver
- SurfaceFlinger //重要
- accessibility
- account
- activity //重要
- alarm //重要
- android.security.keystore
- android.service.gatekeeper.IGateKeeperService
- appops
- appwidget
- assetatlas
- audio //重要
- backup
- battery //重要
- batteryproperties
- batterystats
- bluetooth_manager
- carrier_config
- clipboard
- cneservice
- com.qualcomm.location.izat.IzatService
- com.qualcomm.qti.qseeproxy
- commontime_management
- connectivity
- connectivity_metrics_logger
- connmetrics
- consumer_ir
- content
- contexthub_service
- country_detector
- cpuinfo
- dbinfo
- device_policy
- deviceidle
- devicestoragemonitor
- diskstats
- display //重要
- display.qservice
- dpmservice
- dreams
- drm.drmManager
- dropbox
- eSEPowerManagerService
- ethernet
- extphone
- gfxinfo
- gpu //重要
- graphicsstats
- hardware_properties
- imms
- ims
- input //重要
- input_method //重要
- iphonesubinfo
- isms
- isub
- jobscheduler
- launcherapps
- location
- lock_settings
- mdtp
- media.audio_flinger
- media.audio_policy
- media.camera
- media.camera.proxy
- media.codec
- media.drm
- media.extractor
- media.player
- media.radio
- media.resource_manager
- media.sound_trigger_hw
- media_projection
- media_router
- media_session
- meminfo //输出内存相关,重要
- midi
- mount
- netd
- netd_listener
- netpolicy
- netstats
- network_management
- network_score
- network_time_update_service
- notification
- okay_property
- otadexopt
- package //重要
- permission
- persistent_data_block
- phone
- pinner
- power //电源管理,重要
- processinfo
- procstats
- qti.ims.connectionmanagerservice
- qti.ims.ext
- qtitetherservice
- recovery
- regionalization
- restrictions
- rttmanager
- samplingprofiler
- scheduling_policy
- search
- sensorservice
- serial
- servicediscovery
- shortcut
- simphonebook
- soundtrigger
- statusbar
- telecom
- telephony.registry
- textservices
- trust
- uimode
- updatelock
- usagestats
- usb
- user
- vendor.qcom.PeripheralManager
- vibrator
- voiceinteraction
- vrmanager
- wallpaper //重要
- webviewupdate
- wifi
- wifip2p
- wifiscanner
- window //Windows管理信息,重要
wakelock
wakelock主要是系统为上层提供控制屏幕亮度显示,以及cpu唤醒的一个接口。我们可以通过上面学习的dumpsys命令来查看系统此时存在那些wakelock。
adb shell dumpsys power
- Wake Locks: size=1
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-1s234ms (uid=1000 pid=1495 ws=WorkSource{1000})
此时系统只有一个wakelock,类型为SCREEN_BRIGHT_WAKE_LOCK,所属模块为WIndowManager。下面讲解一下如何使用wakelock。
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); //获取PowerManager
- sWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK //使用power创建一个新的wakelock,执行类型
- | PowerManager.ACQUIRE_CAUSES_WAKEUP
- | PowerManager.ON_AFTER_RELEASE, TAG);
- sWakeLock.acquire(); //使wakelock起作用,当不需要时使用release释放wakelock
任何应用程序使用WakeLock,必须要求android.permission.WAKE_LOCK许可在应用程序的清单上使用<uses-permission>元素。下面为我们可以调用的公共方法。
- Public Methods
- void acquire() --->当你创建这个WakeLock时,确保这个设备按照你的要求保持唤醒的状态。
- void acquire(long timeout) --->当你创建这个WakeLock时,确保这个设备按照你的要求保持唤醒的状态。
- void isHeld()
- void release() ---> 按照你的要求释放cpu或屏幕。
- void setReferenceCounted(boolean value)--->如果需要使用引用计数,则将value设置为true。默认设置为 true,表示当用户申请多少次锁时,就必须释放多少次。
- void setWorkSource(WorkSource ws)
- String toString() --->返回一个简洁的字符串用来将这个对象描述为人们可读懂的。
- void Finalize() --->当垃圾收集器检测到该实例不再运行调用。
wakelock有不同的类型,我们可以根据需要选择不同的wakelock类型。
Flag Value | CPU | Screen | Keyboard |
PARTIAL_WAKE_LOCK | On | Off | Off |
SCREEN_DIM_WAKE_LOCK | On | Dim | Off |
SCREEN_BRIGHT_WAKE_LOCK | On | Bright | Off |
FULL_WAKE_LOCK | On | Bright | Bright |
SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
ON_AFTER_RELEASE:设置了这个标志,当wakelock释放时用户activity计时器会被重置,导致照明持续一段时间。如果你在wacklock条件中循环,这个可以用来减少闪烁
- 03-19 14:58:50.034 319 3145 D kevin_Render: #01 pc 0005f8a5 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::setAnchorTime(long long, long long, long long, bool)+72)
- 03-19 14:58:50.034 319 3145 D kevin_Render: #02 pc 000618c5 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::onNewAudioMediaTime(long long)+88)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #03 pc 00062249 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::onDrainAudioQueue()+764)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #04 pc 00062ec3 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::onMessageReceived(android::sp<android::AMessage> const&)+866)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #05 pc 0000d12d /system/lib/libstagefright_foundation.so (android::ALooperRoster::deliverMessage(android::sp<android::AMessage> const&)+164)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #06 pc 0000cac1 /system/lib/libstagefright_foundation.so (android::ALooper::loop()+216)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #07 pc 00010977 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+110)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #08 pc 00016f5b /system/lib/libc.so (__pthread_start(void*)+30)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #09 pc 00014f7b /system/lib/libc.so (__start_thread+6)
- kevin@kevin-All-Series:~/work/$ addr2line -e out/target/product/miki8163_9003/symbols/system/lib/libmediaplayerservice.so -f -C 00062249
- android::NuPlayer::Renderer::onDrainAudioQueue()
- /home/kevin/work/source/sm8163/sm8163/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp:868
meminfo
当我们查询系统的内存信息除了使用dumpsys命令,还可以直接使用adb shell cat /proc/meminfo- kevin@kevin-All-Series:~/work$ adb shell cat /proc/meminfo
- MemTotal: 1844152 kB //内存的总大小
- MemFree: 41364 kB //空闲内存
- MemAvailable: 230892 kB //可用的内存
- Buffers: 3520 kB
- Cached: 230312 kB //缓存
- SwapCached: 6484 kB
- Active: 538568 kB
- Inactive: 257680 kB
- Active(anon): 426264 kB
- Inactive(anon): 144884 kB
- Active(file): 112304 kB
- Inactive(file): 112796 kB
- Unevictable: 256 kB
- Mlocked: 256 kB
- SwapTotal: 524284 kB
- SwapFree: 156 kB
- Dirty: 44 kB //脏页
- Writeback: 0 kB
- AnonPages: 559864 kB
- Mapped: 216980 kB
- Shmem: 8608 kB
- Slab: 354744 kB
- SReclaimable: 56820 kB
- SUnreclaim: 297924 kB
- KernelStack: 35488 kB
- PageTables: 34172 kB
- NFS_Unstable: 0 kB
- Bounce: 0 kB
- WritebackTmp: 0 kB
- CommitLimit: 1446360 kB
- Committed_AS: 63267272 kB
- VmallocTotal: 244318144 kB
- VmallocUsed: 116780 kB
- VmallocChunk: 244056036 kB
fastboot
Android系统编译后会生成很多的image文件,我们可以通过刷机工具将image烧制到手机中,我们也可以使用fastboot命令很方便的将image文件烧制到系统中。下面为fastboot的使用方法:
1.开机状态下执行
adb reboot bootloader(执行命令后系统会关机重启,进入fastboot模式)
2.烧写system.img
fastboot flash system system.img
如果要烧制boot.img,那么就执行fastboot flash boot boot.img,其他image也一样。
3.重启
fastboot reboot
简单几步就可以快速将我们编译出来的文件烧制到手机中。
bootchart
bootchart是一个用于linux启动过程性能分析的开源软件工具,在系统启动过程自动收集CPU占用率、进程等信息,并以图形方式显示分析结果,可用作指导优化系统启动过程。bootchart详细使用说明请参考《Android7.0 bootchart工具使用说明》
LOG分析
在调试Android系统时如果要实时的查看输出的log信息就可以使用adb logcat -vthreadtime或者adb logcat在终端输出需要的log信息,在5.1及其之前的版本需要adb logcat后需要加上-vthreadtime 意思是将输出时间以及进程线程信息,5.1之后的版本系统自动添加了时间与进程线程信息,直接用adb logcat就可以。
而更多的时候我们需要分析log文件,也就是在系统运行时会将log信息输出在log文件中,以便在出现问题时让开发人员进行分析,下面讲几个场景的关键LOG信息。
开机LOG
在分析开机log时通过根据开机流程进行分段分析,这里省略bootloader中log,首先从执行kernel完成分析,到启动launcher分析结束,来看其中执行了那些过程,如果开机流程出现问题,就可以定位哪个流程出现问题。
- //开始启动init进程,也就是kernel启动完成,取时间戳2.172934s,为启动kernel所耗时.
- [01-01 08:30:04.349] <13>[ 2.172934] c5 init: init started!
- //开始启动zygote,使用时间戳相减4.281027-2.172934计算出启动init进程到启动zygote耗时2.1s.
- [01-01 08:30:04.367] <13>[ 4.281027] c0 init: Starting service 'zygote'...
- //进入zygote,由于kernel时间与android不能相减,所以无法计算启动zygote到进入zygote所花费时间.
- A001-01 08:30:05.036 2810 2810 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
- //进入SystemServer,使用android时间08:30:08.629-08:30:05.036 获得,从进入zygote到SystemServer耗时
- A101-01 08:30:08.629 3285 3285 I SystemServer: Entered the Android system server!
- //开始初始化Package, 使用android时间相减,获取进入SystemServer到初始化Package的耗时.
- A101-01 08:30:09.021 3285 3285 I SystemServer: Package Manager
- //扫描解析应用耗时,可以直接获取1.544 seconds
- A101-01 08:30:10.813 3285 3285 I PackageManager: Time to scan packages: 1.544 seconds
- //开始执行network systemReady函数,使用android时间相减,获取初始化Package完成到开始执行network systemReady函数的耗时.
- A101-01 08:30:14.285 3285 3285 D NetworkManagement: enabling bandwidth control
- //network执行完相关命令,使用android时间相减,获取执行network执行相关命令耗时.
- A101-01 08:30:15.475 3285 3285 I SystemServiceManager: Starting phase 600
- //启动launcher, 使用android时间相减,获取执行network命令完成,到启动launcher耗时
- A101-01 08:30:15.915 3285 3285 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.android.launcher3/.Launcher} from uid 0 on display 0
关机LOG
在分析关机log时,是从长按power键,点击确认关机,到灭屏震动关机。关机主要经过的流程为发送关机广播,关闭AMS,PMS,关闭移动数据,卸载sd卡等流程,最后调用power往底层系统配置中写入对应的信息,底层读取信息,进行关机。
- //按确认键,开始关机
- 01-01 12:49:10.410 1147 1226 I ShutdownThread: shutdown goto shutdownInner
- //发送关机广播,使用android时间相减,获得关机到发送关机广播之间耗时
- 01-01 12:49:10.498 1147 2504 I ShutdownThread: Sending shutdown broadcast...
- //开始shutdown activity manager, 使用android时间相减,获得关机广播处理耗时
- 01-01 12:49:10.637 1147 2504 I ShutdownThread: Shutting down activity manager...
- //开始关闭蜂窝网,使用android时间相减,获得开机shutdown activity manager到关闭蜂窝网耗时
- 01-01 12:49:10.746 1147 2522 W ShutdownThread: Turning off cellular radios...
- //开始关闭Radio,获得关闭蜂窝网到开始关闭Radio耗时
- 01-01 12:49:10.753 1147 2522 I ShutdownThread: Waiting for NFC, Bluetooth and Radio...
- //关闭Radio完成,使用android时间相减,获得关闭Radio耗时,该流程可能耗时较长.重点
- 01-01 12:49:11.255 1147 2522 I ShutdownThread: NFC, Radio and Bluetooth shutdown complete.
- //开始关闭MountService,使用android时间相减,获得关闭Radio完成到关闭MountService耗时.
- 01-01 12:49:11.257 1147 2504 I ShutdownThread: Shutting down MountService
- //关闭MountService完成,使用android时间相减,获得关闭MountService耗时.该流程可能耗时较长.重点
- 01-01 12:49:11.268 1147 1304 W ShutdownThread: Result code 0 from MountService.shutdown
- //调用底层接口,关机完成.
- 01-01 12:49:11.776 1147 2504 I ShutdownThread: Performing low-level shutdown...
首启动应用LOG
在分析分析应用启动问题时,我们通常分析event log信息,使用命令adb logcat -b events,其中的log信息主要为应用的生命周期信息。通过查看生命周期信息来分析,应用是否行为异常。
首次启动
- //开始启动activity
- 07-29 10:26:57.033 1173 1995 I am_create_activity: [0,102422011,29,com.android.dialer/.DialtactsActivity,android.intent.action.MAIN,NULL,NULL,270532608]
- //launcher pause完成。
- 07-29 10:26:57.109 2009 2009 I am_on_paused_called: [0,com.android.launcher3.Launcher]
- //进程开始创建,与开始启动activity时间相减,获得准备工作耗时.
- 07-29 10:26:57.142 1173 1996 I am_proc_start: [0,5164,10038,com.android.dialer,activity,com.android.dialer/.DialtactsActivity]
- //进程bound完成,与进程创建之间这个过程可以理解为进程创建的时间。为创建进程耗时.
- 07-29 10:26:57.195 1173 1404 I am_proc_bound: [0,5164,com.android.dialer]
- //ams向应用发消息进行启动activity操作
- 07-29 10:26:57.199 1173 1404 I am_restart_activity: [0,102422011,29,com.android.dialer/.DialtactsActivity]
- //activity resume执行完成,与restart_activity之间这个可以理解为Activity的生命周期执行时间。为生命周期耗时
- 07-29 10:26:57.394 5164 5164 I am_on_resume_called: [0,com.android.dialer.DialtactsActivity]
- //这里activity显示完成,当前Activity显示过程644ms,整个显示过程644ms。
- //从activity resume完成到这个log之间可以理解为广义上的绘制过程(measure,layout,draw,render)。
- 07-29 10:26:57.757 1173 1356 I am_activity_launch_time: [0,102422011,com.android.dialer/.DialtactsActivity,644,644]
非首次启动
- //开始启动activity,到launcher pause完成。
- 01-01 13:26:59.645 1162 1733 I am_create_activity: [0,233918075,10,com.android.messaging/.ui.conversationlist.ConversationListActivity,android.intent.action.MAIN,NULL,NULL,270532608]
- //launcher pause完成。
- 07-29 10:26:57.109 2009 2009 I am_on_paused_called: [0,com.android.launcher3.Launcher]
- //ams向应用发消息进行启动activity操作,准备工作
- 01-01 13:26:59.710 1162 1439 I am_restart_activity: [0,233918075,10,com.android.messaging/.ui.conversationlist.ConversationListActivity]
- //activity resume执行完成,与restart_activity之间这个可以理解为Activity的生命周期执行时间。
- 01-01 13:26:59.782 2189 2189 I am_on_resume_called: [0,com.android.messaging.ui.conversationlist.ConversationListActivity]
- //这里activity显示完成,当前Activity显示过程168ms,整个显示过程168ms。
- //从activity resume完成到这个log之间可以理解为广义上的绘制过程(measure,layout,draw,render)。
- 01-01 13:26:59.871 1162 1283 I am_activity_launch_time: [0,233918075,com.android.messaging/.ui.conversationlist.ConversationListActivity,168,168]
亮屏关键LOG
- //kernel中断key事件,ScanCode:116为Power键,value:1为down事件
- <6>[41051.961488] c1 [SPRD_KEY_INFO]Key:Power Key ScanCode:116 value:1
- //InputReader获取power键事件,code=116为power键
- 01-02 08:04:44.016 600 643 D InputReader: processEventsLocked: type=1 Count=2 code=116 value=1 deviceId=2
- //Power收到亮屏调用,开始亮屏
- 01-02 08:04:44.037 600 643 I PowerManagerService: Waking up from sleep (uid 1000)...
- //开始block亮屏,直到keyguard与windows绘制完成
- 01-02 08:04:44.052 600 622 I DisplayPowerController: Blocking screen on until initial contents have been drawn.
- //开始绘制keyguard
- 01-02 08:04:44.052 600 622 I WindowManager: Screen turning on...
- //tosuspend_disable()耗时283s,有时为setPowerMode耗时长
- 01-02 08:04:44.347 600 676 D PowerManagerService-JNI: Excessive delay in autosuspend_disable() while
- //yguard绘制完成
- 01-02 08:04:44.504 600 700 D WindowManager: mKeyguardDelegate.ShowListener.onDrawn.
- 01-02 08:04:44.504 600 614 W WindowManager: Setting mKeyguardDrawComplete
- //windows绘制完成
- 01-02 08:04:44.551 600 620 I WindowManager: All windows ready for display!
- 01-02 08:04:44.551 600 614 W WindowManager: Setting mWindowManagerDrawComplete
- //block亮屏,总共blocked亮屏505ms
- 01-02 08:04:44.557 600 622 I DisplayPowerController: Unblocked screen on after 505 ms
- //屏幕亮度,往节点中写亮度值
- 01-02 08:04:44.558 600 676 D LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:set_light_backlight, brightness=25
- 01-02 08:04:44.559 600 676 E LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:write_int, path=/sys/class/backlight/sprd_backlight/brightness, value=25
来电亮屏LOG
- //创建dialer进程
- 12-22 15:46:23.704 595 595 I ActivityManager: Start proc 5067:com.android.dialer/u0a1 for service com.android.dialer/com.android.incallui.InCallServiceImpl
- //来电响铃
- 12-22 15:46:23.736 595 5083 I Telecom : AsyncRingtonePlayer: Play ringtone.
- //启动InCallActivity
- 12-22 15:46:24.410 595 1016 I ActivityManager: START u0 {act=android.intent.action.MAIN flg=0x10040000 cmp=com.android.dialer/com.android.incallui.InCallActivity (has extras)} from uid 10001 on display 0
- //显示InCallActivity
- 12-22 15:46:25.715 595 615 I am_activity_launch_time: [0,134650581,com.android.dialer/com.android.incallui.InCallActivity,1293,1299]
- //power收到亮屏调用
- 12-22 15:46:25.730 595 615 I PowerManagerService: Waking up from sleep due toandroid android.server.wm:TURN_ON (uid 1000)...
- //点亮屏幕
- A012-22 15:46:26.220 595 679 D LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:set_light_backlight, brightness=25
- A012-22 15:46:26.221 595 679 E LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:write_int, path=/sys/class/backlight/sprd_backlight/brightness, value=25
灭屏LOG
- //kernel中断key事件,ScanCode:116为Power键,value:1为down事件
- <6>[42586.507314] c1 [SPRD_KEY_INFO]Key:Power Key ScanCode:116 value:1
- //value:0为up事件
- <6>[42586.660288] c1 [SPRD_KEY_INFO]Key:Power Key ScanCode:116 value:0
- //Input收到power键down事件
- 01-06 13:25:48.460 3339 3447 D InputReader: processEventsLocked: type=1 Count=2 code=116 value=1 deviceId=2
- //Input收到power键up事件
- 01-06 13:25:48.643 3339 3447 D InputReader: processEventsLocked: type=1 Count=2 code=116 value=0 deviceId=2
- //短按power键,power开始灭屏
- 01-06 13:25:48.643 3339 3447 I PowerManagerService: Going to sleep due to power button (uid 1000)...
- //设置全局变量,通知keyguard灭屏了
- 01-06 13:25:48.645 3339 3361 I WindowManager: Screen turned off...
- //设置屏幕亮度为0
- 01-06 13:25:48.645 3339 3493 D LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:set_light_backlight, brightness=0
- 01-06 13:25:48.645 3339 3493 E LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:write_int, path=/sys/class/backlight/sprd_backlight/brightness, value=0
添加LOG信息
java层添加
- import android.util.Log; //导入LOG包
- private static String getActiveSubscriberId(Context context, int subId) {
- final TelephonyManager tele = TelephonyManager.from(context);
- String retVal = tele.getSubscriberId(subId);
- Log.d(TAG, "getActiveSubscriberId=" + retVal + " subId=" + subId); //添加log信息
- return retVal;
- }
如果想知道某行代码是怎么调用过来的,他的调用关系是什么,就可以通过打印堆栈的方式来确认。具体方式如下;
- try {
- throw new Exception("Call Stack Trace");
- } catch (Exception e) {
- Log.i("kevin", "xxx", e);
- }
例如在唤醒屏幕流程,如果想要分析wakeUpInternal是怎么调用过来的,就可以打印堆栈的方式来确认调用关系。
- private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
- int opUid) {
- synchronized (mLock) {
- try {
- throw new Exception("Call Stack Trace");
- } catch (Exception e) {
- Log.i("kevin", "xxx", e);
- }
- if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
- updatePowerStateLocked();
- }
- }
- }
当我们修改好代码后编译services.jar,将services.jar push到手机中,重启,按power键亮灭屏就可以看到如下信息。
C++层添加
如果想要在C++层添加log信息,需要在对应的Android.mk文件中添加下面代码,添加共享库。
- LOCAL_SHARED_LIBRARIES := libutils
用如下log可以打印C++层的信息。
- ALOGD("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
如果要在C++层中打印对应堆栈,使用如下代码:
- #include <utils/CallStack.h>
- CallStack stack;
- stack.update();
- stack.log("kevin");
示例代码如下:
- void NuPlayer::start() {
- CallStack stack;
- stack.update();
- stack.log("kevin");
- (new AMessage(kWhatStart, this))->post();
- }
输出堆栈如下:
可以使用前面学习的addr2line
概述
Framework开发是一项非常繁琐复杂的工作,需要阅读大量的源代码,分析及其多的LOG信息来定位错误位置。这个时候如果使用一些工具或者知道如何定位重要LOG信息,就可以使一些复杂的工作变的简单很多,使我们分析问题的效率变得更快,不再为阅读大量的源代码而感到一筹莫展。本文将针对一些场景讲解如何分析系统LOG信息,如何添加LOG定位错误信息,以及常用工具以及使用方法。
常用工具
HierarchyViewer
HierarchyViewer是随Android SDK发布的工具,位置在sdk的tools文件夹下,名为hierarchyviewer。它是Android自带的非常有用而且使用简单的工具,能够让我们从可视化的角度直观地获得UI布局设计结构和各种属性的信息,帮助我们优化布局设计。打开HierarchyViewer后我们可以看到当前view的布局,如下图所示。
DDMS
DDMS 的全称是Dalvik Debug Monitor Service,是 Android 开发环境中的Dalvik虚拟机调试监控服务。它为我们提供例如:为测试设备截屏,针对特定的进程查看正在运行的线程以及堆信息、Logcat、广播状态信息、模拟电话呼叫、接收SMS、虚拟地理坐标等等。DDMS打开界面如下:
左侧的Devices一栏会列出已连接的设备,点击设备名称左侧三角符号图标会列出该设备运行中的进程的app包名。
模拟按键
使用命令adb shell input keyevent + 对应的键值,可以模拟对应的操作。手机系统中主要的键值如下:
- /** Key code constant: Home key.
- * This key is handled by the framework and is never delivered to applications. */
- public static final int KEYCODE_HOME = 3; //Home键
- /** Key code constant: Back key. */
- public static final int KEYCODE_BACK = 4; //Back键
- /** Key code constant: Call key. */
- public static final int KEYCODE_CALL = 5; //打电话
- /** Key code constant: End Call key. */
- public static final int KEYCODE_ENDCALL = 6; //挂断电话
- /** Key code constant: Volume Up key.
- * Adjusts the speaker volume up. */
- public static final int KEYCODE_VOLUME_UP = 24; //调大声音
- /** Key code constant: Volume Down key.
- * Adjusts the speaker volume down. */
- public static final int KEYCODE_VOLUME_DOWN = 25; //调小声音
- /** Key code constant: Power key. */
- public static final int KEYCODE_POWER = 26; //电源键
- /** Key code constant: Camera key.
- * Used to launch a camera application or take pictures. */
- public static final int KEYCODE_CAMERA = 27; //相机按键
- /** Key code constant: Clear key. */
- public static final int KEYCODE_CLEAR = 28; //清理
- /** Key code constant: Space key. */
- public static final int KEYCODE_SPACE = 62; //空格键
- /** Key code constant: Backspace key.
- * Deletes characters before the insertion point, unlike {@link #KEYCODE_FORWARD_DEL}. */
- public static final int KEYCODE_DEL = 67; //删除键
- /** Key code constant: Menu key. */
- public static final int KEYCODE_MENU = 82; //菜单键
当我们要模拟power键亮灭屏事件就可以执行下面命令:
- adb shell input keyevent 26
模拟别的按键事件同理。
而adb shell getevent / adb shell sendevent是发送对应的事件,包括触屏,按键等事件。
am命令
有时候我们在调试系统时可以在终端使用am命令来发送广播,打开Activity,启动Service等操作,十分方便。am的详细操作如下,我们可以通过adb shell am + 对应命令,就可操作。
- usage: am [subcommand] [options]
- usage: am start [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]
- [--sampling INTERVAL] [-R COUNT] [-S]
- [--track-allocation] [--user <USER_ID> | current] <INTENT> //可以通过该命令启动对应Activity
- am startservice [--user <USER_ID> | current] <INTENT> //启动服务
- am stopservice [--user <USER_ID> | current] <INTENT> //停止服务
- am force-stop [--user <USER_ID> | all | current] <PACKAGE> //通过包名强制停止应用
- am kill [--user <USER_ID> | all | current] <PACKAGE> //根据进程号杀死进程
- am kill-all //杀掉所有后台进程
- am broadcast [--user <USER_ID> | all | current] <INTENT> //发送广播
- am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]
- [--user <USER_ID> | current]
- [--no-window-animation] [--abi <ABI>] <COMPONENT>
- am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE> //抓取traceview
- am profile stop [--user <USER_ID> current] [<PROCESS>] //停止抓取traceview
- am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>
- am set-debug-app [-w] [--persistent] <PACKAGE>
- am clear-debug-app
- am set-watch-heap <PROCESS> <MEM-LIMIT>
- am clear-watch-heap
- am bug-report [--progress]
- am monitor [--gdb <port>]
- am hang [--allow-restart]
- am restart //重启应用
- am idle-maintenance
- am screen-compat [on|off] <PACKAGE>
- am package-importance <PACKAGE>
- am to-uri [INTENT]
- am to-intent-uri [INTENT]
- am to-app-uri [INTENT]
- am switch-user <USER_ID>
- am start-user <USER_ID>
- am unlock-user <USER_ID> [TOKEN_HEX]
- am stop-user [-w] [-f] <USER_ID>
- am stack start <DISPLAY_ID> <INTENT>
- am stack movetask <TASK_ID> <STACK_ID> [true|false] //stack相关
- am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]
- am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]
- am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am stack positiontask <TASK_ID> <STACK_ID> <POSITION>
- am stack list //列出系统中的所有stack
- am stack info <STACK_ID> //stack信息
- am stack remove <STACK_ID> //移除stack
- am task lock <TASK_ID>
- am task lock stop
- am task resizeable <TASK_ID> [0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)]
- am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>
- am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS]
- am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS]
- am get-config
- am suppress-resize-config-changes <true|false>
- am set-inactive [--user <USER_ID>] <PACKAGE> true|false
- am get-inactive [--user <USER_ID>] <PACKAGE>
- am send-trim-memory [--user <USER_ID>] <PROCESS>
- [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]
- am get-current-user
- am start: start an Activity. Options are: //启动Activity详细使用方法
- -D: enable debugging
- -N: enable native debugging
- -W: wait for launch to complete
- --start-profiler <FILE>: start profiler and send results to <FILE>
- --sampling INTERVAL: use sample profiling with INTERVAL microseconds
- between samples (use with --start-profiler)
- -P <FILE>: like above, but profiling stops when app goes idle
- -R: repeat the activity launch <COUNT> times. Prior to each repeat,
- the top activity will be finished.
- -S: force stop the target app before starting the activity
- --track-allocation: enable tracking of object allocations
- --user <USER_ID> | current: Specify which user to run as; if not
- specified then run as the current user.
- --stack <STACK_ID>: Specify into which stack should the activity be put.
- am startservice: start a Service. Options are:
- --user <USER_ID> | current: Specify which user to run as; if not
- specified then run as the current user.
- am stopservice: stop a Service. Options are:
- --user <USER_ID> | current: Specify which user to run as; if not
- specified then run as the current user.
- am force-stop: force stop everything associated with <PACKAGE>.
- --user <USER_ID> | all | current: Specify user to force stop;
- all users if not specified.
- am kill: Kill all processes associated with <PACKAGE>. Only kills.
- processes that are safe to kill -- that is, will not impact the user
- experience.
- --user <USER_ID> | all | current: Specify user whose processes to kill;
- all users if not specified.
- am kill-all: Kill all background processes.
- am broadcast: send a broadcast Intent. Options are:
- --user <USER_ID> | all | current: Specify which user to send to; if not
- specified then send to all users.
- --receiver-permission <PERMISSION>: Require receiver to hold permission.
- am instrument: start an Instrumentation. Typically this target <COMPONENT>
- is the form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there
- is only one instrumentation. Options are:
- -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with
- [-e perf true] to generate raw output for performance measurements.
- -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a
- common form is [-e <testrunner_flag> <value>[,<value>...]].
- -p <FILE>: write profiling data to <FILE>
- -w: wait for instrumentation to finish before returning. Required for
- test runners.
- --user <USER_ID> | current: Specify user instrumentation runs in;
- current user if not specified.
- --no-window-animation: turn off window animations while running.
- --abi <ABI>: Launch the instrumented process with the selected ABI.
- This assumes that the process supports the selected ABI.
- am trace-ipc: Trace IPC transactions.
- start: start tracing IPC transactions.
- stop: stop tracing IPC transactions and dump the results to file.
- --dump-file <FILE>: Specify the file the trace should be dumped to.
- am profile: start and stop profiler on a process. The given <PROCESS> argument
- may be either a process name or pid. Options are:
- --user <USER_ID> | current: When supplying a process name,
- specify user of process to profile; uses current user if not specified.
- am dumpheap: dump the heap of a process. The given <PROCESS> argument may
- be either a process name or pid. Options are:
- -n: dump native heap instead of managed heap
- --user <USER_ID> | current: When supplying a process name,
- specify user of process to dump; uses current user if not specified.
- am set-debug-app: set application <PACKAGE> to debug. Options are:
- -w: wait for debugger when application starts
- --persistent: retain this value
- am clear-debug-app: clear the previously set-debug-app.
- am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or
- above <HEAP-LIMIT> then a heap dump is collected for the user to report
- am clear-watch-heap: clear the previously set-watch-heap.
- am bug-report: request bug report generation; will launch a notification
- when done to select where it should be delivered. Options are:
- --progress: will launch a notification right away to show its progress.
- am monitor: start monitoring for crashes or ANRs.
- --gdb: start gdbserv on the given port at crash/ANR
- am hang: hang the system.
- --allow-restart: allow watchdog to perform normal system restart
- am restart: restart the user-space system.
- am idle-maintenance: perform idle maintenance now.
- am screen-compat: control screen compatibility mode of <PACKAGE>.
- am package-importance: print current importance of <PACKAGE>.
- am to-uri: print the given Intent specification as a URI.
- am to-intent-uri: print the given Intent specification as an intent: URI.
- am to-app-uri: print the given Intent specification as an android-app: URI.
- am switch-user: switch to put USER_ID in the foreground, starting
- execution of that user if it is currently stopped.
- am start-user: start USER_ID in background if it is currently stopped,
- use switch-user if you want to start the user in foreground.
- am stop-user: stop execution of USER_ID, not allowing it to run any
- code until a later explicit start or switch to it.
- -w: wait for stop-user to complete.
- -f: force stop even if there are related users that cannot be stopped.
- am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.
- am stack movetask: move <TASK_ID> from its current stack to the top (true) or bottom (false) of <STACK_ID>.
- am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.
- am stack resize-docked-stack: change docked stack to <LEFT,TOP,RIGHT,BOTTOM>
- and supplying temporary different task bounds indicated by
- <TASK_LEFT,TOP,RIGHT,BOTTOM>
- am stack size-docked-stack-test: test command for sizing docked stack by
- <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom
- applying the optional [DELAY_MS] between each step.
- am stack move-top-activity-to-pinned-stack: moves the top activity from
- <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the
- bounds of the pinned stack.
- am stack positiontask: place <TASK_ID> in <STACK_ID> at <POSITION>
- am stack list: list all of the activity stacks and their sizes.
- am stack info: display the information about activity stack <STACK_ID>.
- am stack remove: remove stack <STACK_ID>.
- am task lock: bring <TASK_ID> to the front and don't allow other tasks to run.
- am task lock stop: end the current task lock.
- am task resizeable: change resizeable mode of <TASK_ID>.
- 0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)
- am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.
- Forces the task to be resizeable and creates a stack if no existing stack
- has the specified bounds.
- am task drag-task-test: test command for dragging/moving <TASK_ID> by
- <STEP_SIZE> increments around the screen applying the optional [DELAY_MS]
- between each step.
- am task size-task-test: test command for sizing <TASK_ID> by <STEP_SIZE> increments within the screen applying the optional [DELAY_MS] between
- each step.
- am get-config: retrieve the configuration and any recent configurations
- of the device.
- am suppress-resize-config-changes: suppresses configuration changes due to
- user resizing an activity/task.
- am set-inactive: sets the inactive state of an app.
- am get-inactive: returns the inactive state of an app.
- am send-trim-memory: send a memory trim event to a <PROCESS>.
- am get-current-user: returns id of the current foreground user.
- <INTENT> specifications include these flags and arguments:
- [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
- [-c <CATEGORY> [-c <CATEGORY>] ...]
- [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
- [--esn <EXTRA_KEY> ...]
- [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
- [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
- [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]
- [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]
- [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]
- [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]
- [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]
- (mutiple extras passed as Integer[])
- [--eial <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]
- (mutiple extras passed as List<Integer>)
- [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
- (mutiple extras passed as Long[])
- [--elal <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
- (mutiple extras passed as List<Long>)
- [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
- (mutiple extras passed as Float[])
- [--efal <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
- (mutiple extras passed as List<Float>)
- [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
- (mutiple extras passed as String[]; to embed a comma into a string,
- escape it using "\,")
- [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
- (mutiple extras passed as List<String>; to embed a comma into a string,
- escape it using "\,")
- [--f <FLAG>]
- [--grant-read-uri-permission] [--grant-write-uri-permission]
- [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]
- [--debug-log-resolution] [--exclude-stopped-packages]
- [--include-stopped-packages]
- [--activity-brought-to-front] [--activity-clear-top]
- [--activity-clear-when-task-reset] [--activity-exclude-from-recents]
- [--activity-launched-from-history] [--activity-multiple-task]
- [--activity-no-animation] [--activity-no-history]
- [--activity-no-user-action] [--activity-previous-is-top]
- [--activity-reorder-to-front] [--activity-reset-task-if-needed]
- [--activity-single-top] [--activity-clear-task]
- [--activity-task-on-home]
- [--receiver-registered-only] [--receiver-replace-pending]
- [--receiver-foreground]
- [--selector]
- [<URI> | <PACKAGE> | <COMPONENT>]
pm命令
当要查询系统中某个应用是否存在,或者存在路径,就可以根据对应的包名来查找对应的apk信息。- usage: pm path [--user USER_ID] PACKAGE
- pm dump PACKAGE //dump某个apk
- pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH] //安装应用
- pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]
- [--install-location 0/1/2]
- [--force-uuid internal|UUID]
- pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]
- pm install-commit SESSION_ID
- pm install-abandon SESSION_ID
- pm uninstall [-k] [--user USER_ID] PACKAGE //卸载应用
- pm set-installer PACKAGE INSTALLER //设置installer
- pm move-package PACKAGE [internal|UUID] //移除package
- pm move-primary-storage [internal|UUID]
- pm clear [--user USER_ID] PACKAGE //清除应用信息
- pm enable [--user USER_ID] PACKAGE_OR_COMPONENT
- pm disable [--user USER_ID] PACKAGE_OR_COMPONENT
- pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT
- pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT
- pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT
- pm hide [--user USER_ID] PACKAGE_OR_COMPONENT
- pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT
- pm grant [--user USER_ID] PACKAGE PERMISSION
- pm revoke [--user USER_ID] PACKAGE PERMISSION
- pm reset-permissions //重置权限
- pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}
- pm get-app-link [--user USER_ID] PACKAGE
- pm set-install-location [0/auto] [1/internal] [2/external] //设置安装路径
- pm get-install-location 获取安装路径
- pm set-permission-enforced PERMISSION [true|false]
- pm trim-caches DESIRED_FREE_SPACE [internal|UUID]
- pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME
- pm remove-user USER_ID
- pm get-max-users
- NOTE: 'pm list' commands have moved! Run 'adb shell cmd package'
- to display the new commands. //使用adb shell pm list packages -f获取系统中所有apk的安装路径
- pm path: print the path to the .apk of the given PACKAGE. //adb shell path +包名,获取apk路径
- pm dump: print system state associated with the given PACKAGE.
- pm install: install a single legacy package
- pm install-create: create an install session
- -l: forward lock application
- -r: replace existing application
- -t: allow test packages
- -i: specify the installer package name
- -s: install application on sdcard
- -f: install application on internal flash
- -d: allow version code downgrade (debuggable packages only)
- -p: partial application install
- -g: grant all runtime permissions
- -S: size in bytes of entire session
- pm install-write: write a package into existing session; path may
- be '-' to read from stdin
- -S: size in bytes of package, required for stdin
- pm install-commit: perform install of fully staged session
- pm install-abandon: abandon session
- pm set-installer: set installer package name
- pm uninstall: removes a package from the system. Options:
- -k: keep the data and cache directories around after package removal.
- pm clear: deletes all data associated with a package.
- pm enable, disable, disable-user, disable-until-used, default-state:
- these commands change the enabled state of a given package or
- component (written as "package/class").
- pm grant, revoke: these commands either grant or revoke permissions
- to apps. The permissions must be declared as used in the app's
- manifest, be runtime permissions (protection level dangerous),
- and the app targeting SDK greater than Lollipop MR1.
- pm reset-permissions: revert all runtime permissions to their default state.
- pm get-install-location: returns the current install location.
- 0 [auto]: Let system decide the best location
- 1 [internal]: Install on internal device storage
- 2 [external]: Install on external media
- pm set-install-location: changes the default install location.
- NOTE: this is only intended for debugging; using this can cause
- applications to break and other undersireable behavior.
- 0 [auto]: Let system decide the best location
- 1 [internal]: Install on internal device storage
- 2 [external]: Install on external media
- pm trim-caches: trim cache files to reach the given free space.
- pm create-user: create a new user with the given USER_NAME,
- printing the new user identifier of the user.
- pm remove-user: remove the user with the given USER_IDENTIFIER,
- deleting all data associated with that user
dumpsys
该命令用于打印出当前系统信息,默认打印出设备中所有service的信息,可以在命令后面加指定的service name。
可以通过adb shell dumpsys + services可以打印出对应系统service的dump信息。可以将某个模块详细信息输出到控制台,可以更加直观的分析。
例如要打印Activity的dump信息:adb shell dumpsys activity
- Currently running services:
- AtCmdFwd
- DockObserver
- SurfaceFlinger //重要
- accessibility
- account
- activity //重要
- alarm //重要
- android.security.keystore
- android.service.gatekeeper.IGateKeeperService
- appops
- appwidget
- assetatlas
- audio //重要
- backup
- battery //重要
- batteryproperties
- batterystats
- bluetooth_manager
- carrier_config
- clipboard
- cneservice
- com.qualcomm.location.izat.IzatService
- com.qualcomm.qti.qseeproxy
- commontime_management
- connectivity
- connectivity_metrics_logger
- connmetrics
- consumer_ir
- content
- contexthub_service
- country_detector
- cpuinfo
- dbinfo
- device_policy
- deviceidle
- devicestoragemonitor
- diskstats
- display //重要
- display.qservice
- dpmservice
- dreams
- drm.drmManager
- dropbox
- eSEPowerManagerService
- ethernet
- extphone
- gfxinfo
- gpu //重要
- graphicsstats
- hardware_properties
- imms
- ims
- input //重要
- input_method //重要
- iphonesubinfo
- isms
- isub
- jobscheduler
- launcherapps
- location
- lock_settings
- mdtp
- media.audio_flinger
- media.audio_policy
- media.camera
- media.camera.proxy
- media.codec
- media.drm
- media.extractor
- media.player
- media.radio
- media.resource_manager
- media.sound_trigger_hw
- media_projection
- media_router
- media_session
- meminfo //输出内存相关,重要
- midi
- mount
- netd
- netd_listener
- netpolicy
- netstats
- network_management
- network_score
- network_time_update_service
- notification
- okay_property
- otadexopt
- package //重要
- permission
- persistent_data_block
- phone
- pinner
- power //电源管理,重要
- processinfo
- procstats
- qti.ims.connectionmanagerservice
- qti.ims.ext
- qtitetherservice
- recovery
- regionalization
- restrictions
- rttmanager
- samplingprofiler
- scheduling_policy
- search
- sensorservice
- serial
- servicediscovery
- shortcut
- simphonebook
- soundtrigger
- statusbar
- telecom
- telephony.registry
- textservices
- trust
- uimode
- updatelock
- usagestats
- usb
- user
- vendor.qcom.PeripheralManager
- vibrator
- voiceinteraction
- vrmanager
- wallpaper //重要
- webviewupdate
- wifi
- wifip2p
- wifiscanner
- window //Windows管理信息,重要
wakelock
wakelock主要是系统为上层提供控制屏幕亮度显示,以及cpu唤醒的一个接口。我们可以通过上面学习的dumpsys命令来查看系统此时存在那些wakelock。
adb shell dumpsys power
- Wake Locks: size=1
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-1s234ms (uid=1000 pid=1495 ws=WorkSource{1000})
此时系统只有一个wakelock,类型为SCREEN_BRIGHT_WAKE_LOCK,所属模块为WIndowManager。下面讲解一下如何使用wakelock。
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); //获取PowerManager
- sWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK //使用power创建一个新的wakelock,执行类型
- | PowerManager.ACQUIRE_CAUSES_WAKEUP
- | PowerManager.ON_AFTER_RELEASE, TAG);
- sWakeLock.acquire(); //使wakelock起作用,当不需要时使用release释放wakelock
任何应用程序使用WakeLock,必须要求android.permission.WAKE_LOCK许可在应用程序的清单上使用<uses-permission>元素。下面为我们可以调用的公共方法。
- Public Methods
- void acquire() --->当你创建这个WakeLock时,确保这个设备按照你的要求保持唤醒的状态。
- void acquire(long timeout) --->当你创建这个WakeLock时,确保这个设备按照你的要求保持唤醒的状态。
- void isHeld()
- void release() ---> 按照你的要求释放cpu或屏幕。
- void setReferenceCounted(boolean value)--->如果需要使用引用计数,则将value设置为true。默认设置为 true,表示当用户申请多少次锁时,就必须释放多少次。
- void setWorkSource(WorkSource ws)
- String toString() --->返回一个简洁的字符串用来将这个对象描述为人们可读懂的。
- void Finalize() --->当垃圾收集器检测到该实例不再运行调用。
wakelock有不同的类型,我们可以根据需要选择不同的wakelock类型。
Flag Value | CPU | Screen | Keyboard |
PARTIAL_WAKE_LOCK | On | Off | Off |
SCREEN_DIM_WAKE_LOCK | On | Dim | Off |
SCREEN_BRIGHT_WAKE_LOCK | On | Bright | Off |
FULL_WAKE_LOCK | On | Bright | Bright |
SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
ON_AFTER_RELEASE:设置了这个标志,当wakelock释放时用户activity计时器会被重置,导致照明持续一段时间。如果你在wacklock条件中循环,这个可以用来减少闪烁
- 03-19 14:58:50.034 319 3145 D kevin_Render: #01 pc 0005f8a5 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::setAnchorTime(long long, long long, long long, bool)+72)
- 03-19 14:58:50.034 319 3145 D kevin_Render: #02 pc 000618c5 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::onNewAudioMediaTime(long long)+88)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #03 pc 00062249 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::onDrainAudioQueue()+764)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #04 pc 00062ec3 /system/lib/libmediaplayerservice.so (android::NuPlayer::Renderer::onMessageReceived(android::sp<android::AMessage> const&)+866)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #05 pc 0000d12d /system/lib/libstagefright_foundation.so (android::ALooperRoster::deliverMessage(android::sp<android::AMessage> const&)+164)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #06 pc 0000cac1 /system/lib/libstagefright_foundation.so (android::ALooper::loop()+216)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #07 pc 00010977 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+110)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #08 pc 00016f5b /system/lib/libc.so (__pthread_start(void*)+30)
- 03-19 14:58:50.035 319 3145 D kevin_Render: #09 pc 00014f7b /system/lib/libc.so (__start_thread+6)
- kevin@kevin-All-Series:~/work/$ addr2line -e out/target/product/miki8163_9003/symbols/system/lib/libmediaplayerservice.so -f -C 00062249
- android::NuPlayer::Renderer::onDrainAudioQueue()
- /home/kevin/work/source/sm8163/sm8163/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp:868
meminfo
当我们查询系统的内存信息除了使用dumpsys命令,还可以直接使用adb shell cat /proc/meminfo- kevin@kevin-All-Series:~/work$ adb shell cat /proc/meminfo
- MemTotal: 1844152 kB //内存的总大小
- MemFree: 41364 kB //空闲内存
- MemAvailable: 230892 kB //可用的内存
- Buffers: 3520 kB
- Cached: 230312 kB //缓存
- SwapCached: 6484 kB
- Active: 538568 kB
- Inactive: 257680 kB
- Active(anon): 426264 kB
- Inactive(anon): 144884 kB
- Active(file): 112304 kB
- Inactive(file): 112796 kB
- Unevictable: 256 kB
- Mlocked: 256 kB
- SwapTotal: 524284 kB
- SwapFree: 156 kB
- Dirty: 44 kB //脏页
- Writeback: 0 kB
- AnonPages: 559864 kB
- Mapped: 216980 kB
- Shmem: 8608 kB
- Slab: 354744 kB
- SReclaimable: 56820 kB
- SUnreclaim: 297924 kB
- KernelStack: 35488 kB
- PageTables: 34172 kB
- NFS_Unstable: 0 kB
- Bounce: 0 kB
- WritebackTmp: 0 kB
- CommitLimit: 1446360 kB
- Committed_AS: 63267272 kB
- VmallocTotal: 244318144 kB
- VmallocUsed: 116780 kB
- VmallocChunk: 244056036 kB
fastboot
Android系统编译后会生成很多的image文件,我们可以通过刷机工具将image烧制到手机中,我们也可以使用fastboot命令很方便的将image文件烧制到系统中。下面为fastboot的使用方法:
1.开机状态下执行
adb reboot bootloader(执行命令后系统会关机重启,进入fastboot模式)
2.烧写system.img
fastboot flash system system.img
如果要烧制boot.img,那么就执行fastboot flash boot boot.img,其他image也一样。
3.重启
fastboot reboot
简单几步就可以快速将我们编译出来的文件烧制到手机中。
bootchart
bootchart是一个用于linux启动过程性能分析的开源软件工具,在系统启动过程自动收集CPU占用率、进程等信息,并以图形方式显示分析结果,可用作指导优化系统启动过程。bootchart详细使用说明请参考《Android7.0 bootchart工具使用说明》
LOG分析
在调试Android系统时如果要实时的查看输出的log信息就可以使用adb logcat -vthreadtime或者adb logcat在终端输出需要的log信息,在5.1及其之前的版本需要adb logcat后需要加上-vthreadtime 意思是将输出时间以及进程线程信息,5.1之后的版本系统自动添加了时间与进程线程信息,直接用adb logcat就可以。
而更多的时候我们需要分析log文件,也就是在系统运行时会将log信息输出在log文件中,以便在出现问题时让开发人员进行分析,下面讲几个场景的关键LOG信息。
开机LOG
在分析开机log时通过根据开机流程进行分段分析,这里省略bootloader中log,首先从执行kernel完成分析,到启动launcher分析结束,来看其中执行了那些过程,如果开机流程出现问题,就可以定位哪个流程出现问题。
- //开始启动init进程,也就是kernel启动完成,取时间戳2.172934s,为启动kernel所耗时.
- [01-01 08:30:04.349] <13>[ 2.172934] c5 init: init started!
- //开始启动zygote,使用时间戳相减4.281027-2.172934计算出启动init进程到启动zygote耗时2.1s.
- [01-01 08:30:04.367] <13>[ 4.281027] c0 init: Starting service 'zygote'...
- //进入zygote,由于kernel时间与android不能相减,所以无法计算启动zygote到进入zygote所花费时间.
- A001-01 08:30:05.036 2810 2810 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
- //进入SystemServer,使用android时间08:30:08.629-08:30:05.036 获得,从进入zygote到SystemServer耗时
- A101-01 08:30:08.629 3285 3285 I SystemServer: Entered the Android system server!
- //开始初始化Package, 使用android时间相减,获取进入SystemServer到初始化Package的耗时.
- A101-01 08:30:09.021 3285 3285 I SystemServer: Package Manager
- //扫描解析应用耗时,可以直接获取1.544 seconds
- A101-01 08:30:10.813 3285 3285 I PackageManager: Time to scan packages: 1.544 seconds
- //开始执行network systemReady函数,使用android时间相减,获取初始化Package完成到开始执行network systemReady函数的耗时.
- A101-01 08:30:14.285 3285 3285 D NetworkManagement: enabling bandwidth control
- //network执行完相关命令,使用android时间相减,获取执行network执行相关命令耗时.
- A101-01 08:30:15.475 3285 3285 I SystemServiceManager: Starting phase 600
- //启动launcher, 使用android时间相减,获取执行network命令完成,到启动launcher耗时
- A101-01 08:30:15.915 3285 3285 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.android.launcher3/.Launcher} from uid 0 on display 0
关机LOG
在分析关机log时,是从长按power键,点击确认关机,到灭屏震动关机。关机主要经过的流程为发送关机广播,关闭AMS,PMS,关闭移动数据,卸载sd卡等流程,最后调用power往底层系统配置中写入对应的信息,底层读取信息,进行关机。
- //按确认键,开始关机
- 01-01 12:49:10.410 1147 1226 I ShutdownThread: shutdown goto shutdownInner
- //发送关机广播,使用android时间相减,获得关机到发送关机广播之间耗时
- 01-01 12:49:10.498 1147 2504 I ShutdownThread: Sending shutdown broadcast...
- //开始shutdown activity manager, 使用android时间相减,获得关机广播处理耗时
- 01-01 12:49:10.637 1147 2504 I ShutdownThread: Shutting down activity manager...
- //开始关闭蜂窝网,使用android时间相减,获得开机shutdown activity manager到关闭蜂窝网耗时
- 01-01 12:49:10.746 1147 2522 W ShutdownThread: Turning off cellular radios...
- //开始关闭Radio,获得关闭蜂窝网到开始关闭Radio耗时
- 01-01 12:49:10.753 1147 2522 I ShutdownThread: Waiting for NFC, Bluetooth and Radio...
- //关闭Radio完成,使用android时间相减,获得关闭Radio耗时,该流程可能耗时较长.重点
- 01-01 12:49:11.255 1147 2522 I ShutdownThread: NFC, Radio and Bluetooth shutdown complete.
- //开始关闭MountService,使用android时间相减,获得关闭Radio完成到关闭MountService耗时.
- 01-01 12:49:11.257 1147 2504 I ShutdownThread: Shutting down MountService
- //关闭MountService完成,使用android时间相减,获得关闭MountService耗时.该流程可能耗时较长.重点
- 01-01 12:49:11.268 1147 1304 W ShutdownThread: Result code 0 from MountService.shutdown
- //调用底层接口,关机完成.
- 01-01 12:49:11.776 1147 2504 I ShutdownThread: Performing low-level shutdown...
首启动应用LOG
在分析分析应用启动问题时,我们通常分析event log信息,使用命令adb logcat -b events,其中的log信息主要为应用的生命周期信息。通过查看生命周期信息来分析,应用是否行为异常。
首次启动
- //开始启动activity
- 07-29 10:26:57.033 1173 1995 I am_create_activity: [0,102422011,29,com.android.dialer/.DialtactsActivity,android.intent.action.MAIN,NULL,NULL,270532608]
- //launcher pause完成。
- 07-29 10:26:57.109 2009 2009 I am_on_paused_called: [0,com.android.launcher3.Launcher]
- //进程开始创建,与开始启动activity时间相减,获得准备工作耗时.
- 07-29 10:26:57.142 1173 1996 I am_proc_start: [0,5164,10038,com.android.dialer,activity,com.android.dialer/.DialtactsActivity]
- //进程bound完成,与进程创建之间这个过程可以理解为进程创建的时间。为创建进程耗时.
- 07-29 10:26:57.195 1173 1404 I am_proc_bound: [0,5164,com.android.dialer]
- //ams向应用发消息进行启动activity操作
- 07-29 10:26:57.199 1173 1404 I am_restart_activity: [0,102422011,29,com.android.dialer/.DialtactsActivity]
- //activity resume执行完成,与restart_activity之间这个可以理解为Activity的生命周期执行时间。为生命周期耗时
- 07-29 10:26:57.394 5164 5164 I am_on_resume_called: [0,com.android.dialer.DialtactsActivity]
- //这里activity显示完成,当前Activity显示过程644ms,整个显示过程644ms。
- //从activity resume完成到这个log之间可以理解为广义上的绘制过程(measure,layout,draw,render)。
- 07-29 10:26:57.757 1173 1356 I am_activity_launch_time: [0,102422011,com.android.dialer/.DialtactsActivity,644,644]
非首次启动
- //开始启动activity,到launcher pause完成。
- 01-01 13:26:59.645 1162 1733 I am_create_activity: [0,233918075,10,com.android.messaging/.ui.conversationlist.ConversationListActivity,android.intent.action.MAIN,NULL,NULL,270532608]
- //launcher pause完成。
- 07-29 10:26:57.109 2009 2009 I am_on_paused_called: [0,com.android.launcher3.Launcher]
- //ams向应用发消息进行启动activity操作,准备工作
- 01-01 13:26:59.710 1162 1439 I am_restart_activity: [0,233918075,10,com.android.messaging/.ui.conversationlist.ConversationListActivity]
- //activity resume执行完成,与restart_activity之间这个可以理解为Activity的生命周期执行时间。
- 01-01 13:26:59.782 2189 2189 I am_on_resume_called: [0,com.android.messaging.ui.conversationlist.ConversationListActivity]
- //这里activity显示完成,当前Activity显示过程168ms,整个显示过程168ms。
- //从activity resume完成到这个log之间可以理解为广义上的绘制过程(measure,layout,draw,render)。
- 01-01 13:26:59.871 1162 1283 I am_activity_launch_time: [0,233918075,com.android.messaging/.ui.conversationlist.ConversationListActivity,168,168]
亮屏关键LOG
- //kernel中断key事件,ScanCode:116为Power键,value:1为down事件
- <6>[41051.961488] c1 [SPRD_KEY_INFO]Key:Power Key ScanCode:116 value:1
- //InputReader获取power键事件,code=116为power键
- 01-02 08:04:44.016 600 643 D InputReader: processEventsLocked: type=1 Count=2 code=116 value=1 deviceId=2
- //Power收到亮屏调用,开始亮屏
- 01-02 08:04:44.037 600 643 I PowerManagerService: Waking up from sleep (uid 1000)...
- //开始block亮屏,直到keyguard与windows绘制完成
- 01-02 08:04:44.052 600 622 I DisplayPowerController: Blocking screen on until initial contents have been drawn.
- //开始绘制keyguard
- 01-02 08:04:44.052 600 622 I WindowManager: Screen turning on...
- //tosuspend_disable()耗时283s,有时为setPowerMode耗时长
- 01-02 08:04:44.347 600 676 D PowerManagerService-JNI: Excessive delay in autosuspend_disable() while
- //yguard绘制完成
- 01-02 08:04:44.504 600 700 D WindowManager: mKeyguardDelegate.ShowListener.onDrawn.
- 01-02 08:04:44.504 600 614 W WindowManager: Setting mKeyguardDrawComplete
- //windows绘制完成
- 01-02 08:04:44.551 600 620 I WindowManager: All windows ready for display!
- 01-02 08:04:44.551 600 614 W WindowManager: Setting mWindowManagerDrawComplete
- //block亮屏,总共blocked亮屏505ms
- 01-02 08:04:44.557 600 622 I DisplayPowerController: Unblocked screen on after 505 ms
- //屏幕亮度,往节点中写亮度值
- 01-02 08:04:44.558 600 676 D LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:set_light_backlight, brightness=25
- 01-02 08:04:44.559 600 676 E LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:write_int, path=/sys/class/backlight/sprd_backlight/brightness, value=25
来电亮屏LOG
- //创建dialer进程
- 12-22 15:46:23.704 595 595 I ActivityManager: Start proc 5067:com.android.dialer/u0a1 for service com.android.dialer/com.android.incallui.InCallServiceImpl
- //来电响铃
- 12-22 15:46:23.736 595 5083 I Telecom : AsyncRingtonePlayer: Play ringtone.
- //启动InCallActivity
- 12-22 15:46:24.410 595 1016 I ActivityManager: START u0 {act=android.intent.action.MAIN flg=0x10040000 cmp=com.android.dialer/com.android.incallui.InCallActivity (has extras)} from uid 10001 on display 0
- //显示InCallActivity
- 12-22 15:46:25.715 595 615 I am_activity_launch_time: [0,134650581,com.android.dialer/com.android.incallui.InCallActivity,1293,1299]
- //power收到亮屏调用
- 12-22 15:46:25.730 595 615 I PowerManagerService: Waking up from sleep due toandroid android.server.wm:TURN_ON (uid 1000)...
- //点亮屏幕
- A012-22 15:46:26.220 595 679 D LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:set_light_backlight, brightness=25
- A012-22 15:46:26.221 595 679 E LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:write_int, path=/sys/class/backlight/sprd_backlight/brightness, value=25
灭屏LOG
- //kernel中断key事件,ScanCode:116为Power键,value:1为down事件
- <6>[42586.507314] c1 [SPRD_KEY_INFO]Key:Power Key ScanCode:116 value:1
- //value:0为up事件
- <6>[42586.660288] c1 [SPRD_KEY_INFO]Key:Power Key ScanCode:116 value:0
- //Input收到power键down事件
- 01-06 13:25:48.460 3339 3447 D InputReader: processEventsLocked: type=1 Count=2 code=116 value=1 deviceId=2
- //Input收到power键up事件
- 01-06 13:25:48.643 3339 3447 D InputReader: processEventsLocked: type=1 Count=2 code=116 value=0 deviceId=2
- //短按power键,power开始灭屏
- 01-06 13:25:48.643 3339 3447 I PowerManagerService: Going to sleep due to power button (uid 1000)...
- //设置全局变量,通知keyguard灭屏了
- 01-06 13:25:48.645 3339 3361 I WindowManager: Screen turned off...
- //设置屏幕亮度为0
- 01-06 13:25:48.645 3339 3493 D LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:set_light_backlight, brightness=0
- 01-06 13:25:48.645 3339 3493 E LIGHTS : file:vendor/sprd/modules/lights/lights.c, func:write_int, path=/sys/class/backlight/sprd_backlight/brightness, value=0
添加LOG信息
java层添加
- import android.util.Log; //导入LOG包
- private static String getActiveSubscriberId(Context context, int subId) {
- final TelephonyManager tele = TelephonyManager.from(context);
- String retVal = tele.getSubscriberId(subId);
- Log.d(TAG, "getActiveSubscriberId=" + retVal + " subId=" + subId); //添加log信息
- return retVal;
- }
如果想知道某行代码是怎么调用过来的,他的调用关系是什么,就可以通过打印堆栈的方式来确认。具体方式如下;
- try {
- throw new Exception("Call Stack Trace");
- } catch (Exception e) {
- Log.i("kevin", "xxx", e);
- }
例如在唤醒屏幕流程,如果想要分析wakeUpInternal是怎么调用过来的,就可以打印堆栈的方式来确认调用关系。
- private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
- int opUid) {
- synchronized (mLock) {
- try {
- throw new Exception("Call Stack Trace");
- } catch (Exception e) {
- Log.i("kevin", "xxx", e);
- }
- if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
- updatePowerStateLocked();
- }
- }
- }
当我们修改好代码后编译services.jar,将services.jar push到手机中,重启,按power键亮灭屏就可以看到如下信息。
C++层添加
如果想要在C++层添加log信息,需要在对应的Android.mk文件中添加下面代码,添加共享库。
- LOCAL_SHARED_LIBRARIES := libutils
用如下log可以打印C++层的信息。
- ALOGD("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
如果要在C++层中打印对应堆栈,使用如下代码:
- #include <utils/CallStack.h>
- CallStack stack;
- stack.update();
- stack.log("kevin");
示例代码如下:
- void NuPlayer::start() {
- CallStack stack;
- stack.update();
- stack.log("kevin");
- (new AMessage(kWhatStart, this))->post();
- }
输出堆栈如下:
可以使用前面学习的addr2line