dumpsys
是一款在Android设备上运行并提供有关系统服务信息的工具。您可以从adb命令行调用dumpsys
以获取连接设备上运行的所有系统服务的诊断输出。此输出通常比您想要的更冗长,因此请使用下面介绍的命令行选项来获取仅用于您感兴趣的系统服务的输出。本页还介绍了如何使用dumpsys
来完成常见任务,例如检查输入, RAM,电池或网络诊断
常用的dumpsys的使用语法如下:
adb shell dumpsys [-t timeout] [--help | -l | --skip services | service [arguments] | -c | -h]
得到你的连接设备上所有系统服务的诊断输出,简单的运行`adb shell dumpsys.`然而这个输出信息比你想要的多得多,为了管理输出,你可以在命令中添加指定的服务,例如下面的命令,提供输出组件的系统数据,例如:触摸屏幕或者内置键盘。
adb shell dumpsys input
你可以使用`dumpsys`得到完整的系统服务,使用如下命令:
adb shell dumpsys -l
当使用dumpsys下面的表列表命令选项是可以获得的:
Option | Description |
---|---|
-t timeout |
以 秒为单位,指定超时周期,如果未指定,默认是10s |
--help |
打印 dumpsys 工具的帮助文本. |
-l |
和 dumpsys 一起使用列出完整的系统服务. |
--skip services |
指定你不想包含的 services输出. |
service [arguments] |
指定你想要的 service输出. 一些服务大概有 arguments选项. 你可以学习关于这个选项arguments通过使用service的 -h 选项 , 演示如下: adb shell dumpsys procstats -h |
-c |
当指定某些服务,增加这个选项以机器友好的格式输出数据 |
-h |
对于某些服务看以帮助文本和额外的选项信息 |
检测input诊断
指定input服务,如下所示,dumps 系统输入设备的状态,如触摸屏幕,内置键盘,输入事件的处理
adb shell dumpsys input
这个输出的变化依赖连接设备的Android版本,下面的部分描述了您通常看到的信息类型。
Event hub state
下面的示例是你可能在检测Event hub state
可能看到的输入信息
INPUT MANAGER (dumpsys input)
Event Hub State:
BuiltInKeyboardId: -2
Devices:
-1: Virtual
Classes: 0x40000023
Path:
Descriptor: a718a782d34bc767f4689c232d64d527998ea7fd
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Virtual.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
1: msm8974-taiko-mtp-snd-card Headset Jack
Classes: 0x00000080
Path: /dev/input/event5
Descriptor: c8e3782483b4837ead6602e20483c46ff801112c
Location: ALSA
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile:
KeyCharacterMapFile:
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
2: msm8974-taiko-mtp-snd-card Button Jack
Classes: 0x00000001
Path: /dev/input/event4
Descriptor: 96fe62b244c555351ec576b282232e787fb42bab
Location: ALSA
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/msm8974-taiko-mtp-snd-card_Button_Jack.kl
KeyCharacterMapFile: /system/usr/keychars/msm8974-taiko-mtp-snd-card_Button_Jack.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
3: hs_detect
Classes: 0x00000081
Path: /dev/input/event3
Descriptor: 485d69228e24f5e46da1598745890b214130dbc4
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0001, product=0x0001, version=0x0001
KeyLayoutFile: /system/usr/keylayout/hs_detect.kl
KeyCharacterMapFile: /system/usr/keychars/hs_detect.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
...
Input reader state
InputReader负责从内核解码输入事件。它的状态转储显示了关于每个输入设备的配置信息,以及最近发生的状态变化,比如按键或触摸屏幕上的触摸。
下面的示例展示了触摸屏的输出。请注意该设备的分辨率和所使用的校准参数的信息
Input Reader State
...
Device 6: Melfas MMSxxx Touchscreen
IsExternal: false
Sources: 0x00001002
KeyboardType: 0
Motion Ranges:
X: source=0x00001002, min=0.000, max=719.001, flat=0.000, fuzz=0.999
Y: source=0x00001002, min=0.000, max=1279.001, flat=0.000, fuzz=0.999
PRESSURE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000
SIZE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000
TOUCH_MAJOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
TOUCH_MINOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
TOOL_MAJOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
TOOL_MINOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
Touch Input Mapper:
Parameters:
GestureMode: spots
DeviceType: touchScreen
AssociatedDisplay: id=0, isExternal=false
OrientationAware: true
Raw Touch Axes:
X: min=0, max=720, flat=0, fuzz=0, resolution=0
Y: min=0, max=1280, flat=0, fuzz=0, resolution=0
Pressure: min=0, max=255, flat=0, fuzz=0, resolution=0
TouchMajor: min=0, max=30, flat=0, fuzz=0, resolution=0
TouchMinor: unknown range
ToolMajor: unknown range
ToolMinor: unknown range
Orientation: unknown range
Distance: unknown range
TiltX: unknown range
TiltY: unknown range
TrackingId: min=0, max=65535, flat=0, fuzz=0, resolution=0
Slot: min=0, max=9, flat=0, fuzz=0, resolution=0
Calibration:
touch.size.calibration: diameter
touch.size.scale: 10.000
touch.size.bias: 0.000
touch.size.isSummed: false
touch.pressure.calibration: amplitude
touch.pressure.scale: 0.005
touch.orientation.calibration: none
touch.distance.calibration: none
SurfaceWidth: 720px
SurfaceHeight: 1280px
SurfaceOrientation: 0
Translation and Scaling Factors:
XScale: 0.999
YScale: 0.999
XPrecision: 1.001
YPrecision: 1.001
GeometricScale: 0.999
PressureScale: 0.005
SizeScale: 0.033
OrientationCenter: 0.000
OrientationScale: 0.000
DistanceScale: 0.000
HaveTilt: false
TiltXCenter: 0.000
TiltXScale: 0.000
TiltYCenter: 0.000
TiltYScale: 0.000
Last Button S
ate: 0x00000000
Last Raw Touch: pointerCount=0
Last Cooked Touch: pointerCount=0
在输入读取器状态转储的末尾,有一些关于全局配置参数的信息,比如tap interval
Configuration:
ExcludedDeviceNames: []
VirtualKeyQuietTime: 0.0ms
PointerVelocityControlParameters: scale=1.000, lowThreshold=500.000, highThreshold=3000.000, acceleration=3.000
WheelVelocityControlParameters: scale=1.000, lowThreshold=15.000, highThreshold=50.000, acceleration=4.000
PointerGesture:
Enabled: true
QuietInterval: 100.0ms
DragMinSwitchSpeed: 50.0px/s
TapInterval: 150.0ms
TapDragInterval: 300.0ms
TapSlop: 20.0px
MultitouchSettleInterval: 100.0ms
MultitouchMinDistance: 15.0px
SwipeTransitionAngleCosine: 0.3
SwipeMaxWidthRatio: 0.2
MovementSpeedRatio: 0.8
ZoomSpeedRatio: 0.3
Input dispatcher state
InputDispatcher
的责任是负责发送input事件到应用程序,如下输出所示,
它的状态转储显示了被触碰的窗口的信息、输入队列的状态、ANR是否正在进行中,等等。
Input Dispatcher State:
DispatchEnabled: 1
DispatchFrozen: 0
FocusedApplication:
FocusedWindow: name='Window{3fb06dc3 u0 StatusBar}'
TouchStates:
Windows:
0: name='Window{357bbbfe u0 SearchPanel}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01820100, type=0x000007e8, layer=211000, frame=[0,0][1080,1920], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
1: name='Window{3b14c0ca u0 NavigationBar}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01840068, type=0x000007e3, layer=201000, frame=[0,1776][1080,1920], scale=1.000000, touchableRegion=[0,1776][1080,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
2: name='Window{2c7e849c u0 com.vito.lux}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x0089031a, type=0x000007d6, layer=191000, frame=[-495,-147][1575,1923], scale=1.000000, touchableRegion=[-495,-147][1575,1923], inputFeatures=0x00000000, ownerPid=4697, ownerUid=10084, dispatchingTimeout=5000.000ms
...
MonitoringChannels:
0: 'WindowManager (server)'
RecentQueue: length=10
MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (335.0, 1465.0)]), policyFlags=0x62000000, age=217264.0ms
MotionEvent(deviceId=4, source=0x00001002, action=1, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (335.0, 1465.0)]), policyFlags=0x62000000, age=217255.7ms
MotionEvent(deviceId=4, source=0x00001002, action=0, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (330.0, 1283.0)]), policyFlags=0x62000000, age=216805.0ms
...
PendingEvent:
InboundQueue: <empty>
ReplacedKeys: <empty>
Connections:
0: channelName='WindowManager (server)', windowName='monitor', status=NORMAL, monitor=true, inputPublisherBlocked=false
OutboundQueue: <empty>
WaitQueue: <empty>
1: channelName='278c1d65 KeyguardScrim (server)', windowName='Window{278c1d65 u0 KeyguardScrim}', status=NORMAL, monitor=false, inputPublisherBlocked=false
OutboundQueue: <empty>
WaitQueue: <empty>
2: channelName='357bbbfe SearchPanel (server)', windowName='Window{357bbbfe u0 SearchPanel}', status=NORMAL, monitor=false, inputPublisherBlocked=false
OutboundQueue: <empty>
WaitQueue: <empty>
...
AppSwitch: not pending
7: channelName='2280455f com.google.android.gm/com.google.android.gm.ConversationListActivityGmail (server)', windowName='Window{2280455f u0 com.google.android.gm/com.google.android.gm.ConversationListActivityGmail}', status=NORMAL, monitor=false, inputPublisherBlocked=false
OutboundQueue: <empty>
WaitQueue: <empty>
8: channelName='1a7be08a com.android.systemui/com.android.systemui.recents.RecentsActivity (server)', windowName='Window{1a7be08a u0 com.android.systemui/com.android.systemui.recents.RecentsActivity EXITING}', status=NORMAL, monitor=false, inputPublisherBlocked=false
OutboundQueue: <empty>
WaitQueue: <empty>
9: channelName='3b14c0ca NavigationBar (server)', windowName='Window{3b14c0ca u0 NavigationBar}', status=NORMAL, monitor=false, inputPublisherBlocked=false
OutboundQueue: <empty>
WaitQueue: <empty>
...
Configuration:
KeyRepeatDelay: 50.0ms
KeyRepeatTimeout: 500.0ms
下面是检查输入服务的各种输出时要考虑的事项列表:
Event hub state:
Classes
字段与EventHub.h中的flag一致, BuiltInKeyboardId
要正确,如果这个设备没有内置键盘,这个id值一定要是-2,否则,它应该是内置键盘的idBuiltInKeyboardId
不是-2,但它应该是,那么您将丢失一个关键字符映射文件,用于特定的函数键盘。特殊功能键盘设备应该有key字符映射文件,其中只包含行类型SPECIAL_FUNCTION
(这就是我们在上面提到的文件tuna-gpio-keykad.kcm
中的内容。Input reader state:
Input dispatcher state:
TouchStates
行正确地标识了您所接触到的窗口警告: 如果您使用`apksigner`签署APK并对APK进行进一步更改,APK的签名将无效。因此,在签署APK之前,您必须使用`zipalign`等工具。.
Usage
Sign an APK
使用apksigner
签名apk的语法如下:
apksigner sign --ks keystore.jks |
--key key.pk8 --cert cert.x509.pem
[signer_options] app-name.apk
当你使用apksigner工具签名时,你必须提供私钥和证书。你可以通过两种不同的方法包含这些:
--ks
选项指定私钥文件和证书,分别使用--key
and --cert
选项。私钥文件必须使用PKCS #8格式,认证文件必须使用X.509格式
通常,您只使用一个签署者签署APK。如果您需要使用多个签署者签署APK,那么使用 --next-signer
选项将一般选项集分离出来,以应用于每个签名者:
apksigner sign [signer_1_options] --next-signer [signer_2_options] app-name.apk
验证APK的签名
确认APK的签名将在受支持的平台上成功验证的语法如下:
apksigner verify [options] app-name.apk
Options
下面的列表包括apk签署工具支持的每个命令的选项集
Sign command
General options
下面的选项指定基本的设置应用于签名:
--out
你想保存签名文件的位置。如果没有明确指定,apk在当前命令行所在目录签名。
--min-sdk-version
apksigner
使用的最低的Android框架API级别来确认APK的签名将被验证。更高的值允许该工具在签署应用时使用更强的安全参数,但将APK的可用性限制在运行最新版本Android的设备上。默认情况下,apksigner
从应用的清单文件中使用minSdkVersion
属性的值。
--max-sdk-version
apksigner
使用的最高的Android框架API级别来确认APK的签名将被验证。默认的,这个工具尽可能使用最好的API等级。
--v1-signing-enabled
决定apksigner
是否使用传统的基于jar的签名方案来签署给定的APK包。默认情况下,该工具使用--max-sdk-version
和--min-sdk-version
的值来决定何时应用这个签名方案。
--v2-signing-enabled
决定 apksigner
是否使用 APK Signature Scheme v2 来签署给定的apk包。默认情况下,该工具使用--max-sdk-version
和--min-sdk-version
的值来决定何时应用这个签名方案。
-v, --verbose
使用详细的输出模式
Per-signer options
下面的选项指定特殊签名者的配置,这不是必须的,如果你签名你的apk仅仅使用一个签署者
--next-signer
为每一个签署者指定不同的常用选项
--v1-signer-name
为当前签名者提供JAR-based签名的文件的基本名称。默认情况下,apksigner
使用KeyStore 的密钥别名或该签名者的密钥文件的basename。
秘钥和认证选项
下面的选项指定签名者的私钥和认证:
--ks
签名者的私钥和证书链属于给定的Java-based 的KeyStore文件中。如果filename被设置为“NONE”
,包含钥匙和证书的密钥库不需要指定的文件,这是PKCS #11密钥存储库的情况。
--ks-key-alias
在KeyStore中代表签名者的私钥和证书数据的别名。如果与签名者关联的密钥存储库包含多个密钥,则必须指定该选项。
--ks-pass
KeyStore 的密码包含私钥和认证,你必须提供一个密码打开KeyStore 。apksigner
支持以下格式:
pass:
:与apksigner sign
命令的其余部分一起提供的密码env:
:密码存储在给定的环境变量中file:
:密码在给定文件中为单行存储stdin
:密码在标准的输出流作为一个单行,这是-ks-pass.
默认的行为注意:如果您在同一个文件中包含多个密码,请在单独的行中指定它们。apksigner
工具根据您指定签署者的顺序将密码与APK的签署者联系起来。如果您为一个签名者提供了两个密码,那么apksigner
将第一个密码解释为KeyStore 密码,第二个密码作为密钥密码。
--ks-type
Type或者algorithm 与KeyStore的私钥和证书相关联。默认情况下,apksigner
使用在安全属性文件中keystore.type
常量作为type.
--ks-provider-name
在请求签署者的KeyStore实现时使用JCA提供的名称。默认情况下,apksigner
使用的是最高优先级的提供者。
--ks-provider-class
在请求签署者的KeyStore实现时使用JCA提供者的完整类名。这个选项作为--ks-provider-name
的另一种选择,默认情况下,apksigner
使用由--ks-provider-name
选项指定的提供者。
--ks-provider-arg
字符串value作为JCA 提供的类的构造的参数。类本身定义在--ks-provider-class
选项。默认的,使用类的空参数构造
--key
包含签名者的私钥的文件名称。这个文件必须是PKCS #8 DER格式,如果这个key是password-protected,apksigner
使用标准的输入提示密码,除非你使用--key-pass
选项指定不同的输入格式
--cert
包含签名者的认证链的文件名。这个文件必须是 X.509 PEM or DER格式。
Verify command
--print-certs
显示apk签名证书的信息
--min-sdk-version
apksigner 使用的最低的Android框架API级别,以确认APK的签名将被验证。当签名app时更高的值允许这个工具使用更强的安全等级参数,但是限制app运行在更多的设备上。默认的,apksigner
使用apk清单文件minSdkVersion
属性的值。
--max-sdk-version
apksigner
使用的最高的Android框架API级别来确认APK的签名将被验证。默认情况下,该工具使用最高的API级别。
-v, --verbose
使用详细的输出模式
-Werr
将警告视为错误。
Examples
Sign an APK
仅仅使用release.jks
签名apk:
apksigner sign --ks release.jks app.apk
签名一个apk使用私钥和证书,保存在单独的文件:
apksigner sign --key release.pk8 --cert release.x509.pem app.apk
签名一个apk使用两个keystore:
apksigner sign --ks first-release-key.jks --next-signer --ks second-release-key.jks app.apk
验证一个apk的签名
检查APK的签名是否会在APK支持的所有Android平台上被确认为有效:
apksigner verify app.apk
检查APK的签名是否在Android 4.0.3(API级15)和更高版本中被确认为有效:
apksigner verify --min-sdk-version 15 app.apk
zipalign是一个对其工具,为Android apk文件提供了重要的优化。这样做的目的是为了确保所有未压缩的数据都以特定的对齐方式开始,相对于文件的开始。具体地说,它会导致APK中的所有未压缩数据,比如图像或原始文件,在4字节边界上对齐。这允许直接使用mmap()访问所有部分,即使它们包含有对齐限制的二进制数据。这样做的好处是减少了运行应用程序时消耗的RAM数量
这个工具应用总是在你的apk分发到用户手中时被使用。Android编译工具为你处理它,AndroidStudio自动使用zipalign帮你对齐。
您必须在应用程序构建过程的两个特定点之一使用zipalign
,这取决于您使用的是哪种应用程序签名工具:
apksigner
,zipalign
jarsigner
,必须在签署APK之后使用zipalign
Usage
对齐infile.apk
保存至outfile.apk
zipalign [-f] [-v] <alignment> infile.apk outfile.apk
确认existing.apk
的对齐
zipalign -c -v <alignment> existing.apk
是一个定义字节对齐边界的整体,这必须始终是4(提供32位对齐),否则它实际上什么也不做。
Flags:
-f :
覆盖已经存在的outfile.zip
-v :
详细输出-p :
outfile.zip应该为infile.zip中的所有共享对象文件使用相同的页面对齐方式。、-c :
确认给定文件的对齐