androidprocnet
❶ Android性能测试(内存、cpu、fps、流量、GPU、电量)——adb篇
3)查看进程列表:adb shell "ps",同时也能获取到应用的UID,方式如下(不需root权限):
u0_a开头的都是Android的应用进程,Android的应用的UID是从10000开始,到19999结束,可以在Process.java中查看到(FIRST_APPLICATION_UID和LAST_APPLICATION_UID),u0_a后面的数字就是该应用的UID值减去FIRST_APPLICATION_UID所得的值,所以,对于截图这个应用进程,它是u0_a155,按前面的规制,它的UID就是155 + FIRST_APPLICATION_UID = 10155。
VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
使用 adb shell "mpsys meminfo -s <pakagename | pid>"命令,输出结果分以下4部分:
PS:在apk内调用运行获取其他app的内存数据则需要root权限
adb命令:adb shell mpsys gfxinfo <package | pid>
正常情况下帧率应该在16.67ms左右,1秒60帧,执行结果如下:
详细计算方法如下:
还有一个命令是: adb shell mpsys SurfaceFlinger --latency LayerName
其中LayerName在各个不同系统中获取的命令是不一样的
在Android 6系统直接就是SurfaceView
在Android 7系统中可以通过 mpsys window windows | grep mSurface | grep SurfaceView 然后通过数据截取到
在Android 8系统中可以通过 mpsys SurfaceFlinger | grep android包名获取到
执行命令结果如下:
计算方法比较简单,一般打印出来的数据是129行(部分机型打印两次257行,但是第一部分是无效数据,取后半部分),取len-2的第一列数据为end_time,取len-128的第一列数据为start_time
fps = 127/((end_time - start_time) / 1000000.0)
至于为啥要取第一列数据,这里不做过多介绍,欢迎参看这两篇文章
老罗的文章SurfaceView原理
Android性能测试之fps获取
至于为啥要处于1000000,因为命令打印出来的是纳秒单位,要转为毫秒进行计算,127就是因为命令一次打印出来127帧的数据而已
有两种方法可以获取
1) adb shell "top -n 5 | grep <package | pid>" ,第三列就是实时监控的CPU占用率(-n 指定执行次数,不需root权限),这边top命令执行需要2到3s左右,一般可以采用busybox 的top命令执行,效率会快很多
2) adb shell "mpsys cpuinfo | grep <package | pid>"
两种方法直接区别在于,top是持续监控状态,而mpsys cpuinfo获取的实时CPU占用率数据
adb命令:adb shell "mpsys batterystats < package | pid>" (Android 5.0后引入)
获取单个应用的耗电量信息,具体返回结果待研究
adb命令:adb shell "mpsys battery"
出现信息解读:
AC powered:false 是否连接AC(电源)充电线
USB powered:true 是否连接USB(PC或笔记本USB插口)充电
Wireless powered:false 是否使用了无线电源
status: 1 电池状态,2为充电状态,其他为非充电状态
level:58 电量(%)
scale: 100. 电量最大数值
voltage: 3977 当前电压(mV)
current now: -335232. 当前电流(mA)
temperature:355 电池温度,单位为0.1摄氏度
adb 命令:adb shell "mpsys< package | pid> | grep UID" [通过ps命令,获取app的UID(安装后唯一且固定)]
adb shell cat /proc/uid_stat/UID/tcp_rcv [cat为查看命令,读取tcp_rcv获取应用接收流量信息(设备重启后清零)]
adb shell cat /proc/uid_stat/UID/tcp_snd [cat为查看命令,读取tcp_snd获取应用发送流量信息(设备重启后清零)]
计算流量消耗步骤:
或者还有一种方式获取应用流量消耗:
首先判断类型:
cat /sys/class/thermal/thermal_zone*/type
只有红框框出来的是有效的
cat /sys/class/thermal/thermal_zone*/temp
获取CPU温度
mpsys battery | grep temperature 单位0.1摄氏度
获取/proc/stat文件内容(无权限限制)
总的cpu时间片是 total = user+nice+system+idle+iowait+irq+softirq
忙碌时间为 notidle = user+nice+system +iowait+irq+softirq
cpu使用率计算方法为,先取开始的total值和忙碌时间notidle,隔一段时间片,再取一次计算total2,notidle2, cpuuse = (notidle2 – notidle) * 100 / (total2 - total)%
PS:由于Android 8权限收紧,在Android 8系统手机内apk内读取文件内容为空,需要shell权限才可获取文件内容,下同
读/sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq文件的值,X不定,看是几核手机,scaling_cur_freq是否存在也不一定,需要判断
至于为啥不取cpuinfo_cur_freq文件的值,原因是android 6,7系统获取的时候,这个文件shell没有读取权限,需要root权限
参考文章: https://blog.csdn.net/long_meng/article/details/45934899
Android 6,7系统可执行
mpsys window windows | grep "mCurrentFocus"
执行结果一般为类似:
mCurrentFocus=Window{81caaa5 u0 com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity}
按照一定规则把com.tencent.mobileqq提取出来即可
直接apk内读取文件即可,不需要shell权限(支持到Android8)
Gpu使用率获取:会得到两个值,(前一个/后一个)*100%=使用率
adb shell cat /sys/class/kgsl/kgsl-3d0/gpubusy
Gpu工作频率:
adb shell cat /sys/class/kgsl/kgsl-3d0/gpuclk
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/cur_freq
Gpu最大、最小工作频率:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
Gpu可用频率
adb shell cat /sys/class/kgsl/kgsl-3d0/gpu_available_frequencies
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/available_frequencies
Gpu可用工作模式:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/available_governors
Gpu当前工作模式:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/governor
❷ 如何在android程序中执行adb shell命令
android程序执行adbshell命令(实例源码)packagenet.gimite.nativeexe;importjava.io.BufferedReader;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.net.HttpURLConnection;importjava.net.MalformedURLException;importjava.net.URL;importnet.gimite.nativeexe.R;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.*;{privateTextViewoutputView;privateButtonlocalRunButton;privateEditTextlocalPathEdit;privateHandlerhandler=newHandler();privateEditTexturlEdit;privateButtonremoteRunButton;/**.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);outputView=(TextView)findViewById(R.id.outputView);localPathEdit=(EditText)findViewById(R.id.localPathEdit);localRunButton=(Button)findViewById(R.id.localRunButton);localRunButton.setOnClickListener(onLocalRunButtonClick);}=newOnClickListener(){publicvoidonClick(Viewv){Stringoutput=exec(localPathEdit.getText().toString());output(output);//try{//////Processprocess=Runtime.getRuntime().exec(localPathEdit.getText().toString());////}catch(IOExceptione){////TODOAuto-generatedcatchblock//e.printStackTrace();//}}};//ExecutesUNIXcommand.privateStringexec(Stringcommand){try{Processprocess=Runtime.getRuntime().exec(command);BufferedReaderreader=newBufferedReader(newInputStreamReader(process.getInputStream()));intread;char[]buffer=newchar[4096];StringBufferoutput=newStringBuffer();while((read=reader.read(buffer))>0){output.append(buffer,0,read);}reader.close();process.waitFor();returnoutput.toString();}catch(IOExceptione){thrownewRuntimeException(e);}catch(InterruptedExceptione){thrownewRuntimeException(e);}}privatevoiddownload(StringurlStr,StringlocalPath){try{URLurl=newURL(urlStr);HttpURLConnectionurlconn=(HttpURLConnection)url.openConnection();urlconn.setRequestMethod("GET");urlconn.setInstanceFollowRedirects(true);urlconn.connect();InputStreamin=urlconn.getInputStream();FileOutputStreamout=newFileOutputStream(localPath);intread;byte[]buffer=newbyte[4096];while((read=in.read(buffer))>0){out.write(buffer,0,read);}out.close();in.close();urlconn.disconnect();}catch(MalformedURLExceptione){thrownewRuntimeException(e);}catch(IOExceptione){thrownewRuntimeException(e);}}privatevoidoutput(finalStringstr){Runnableproc=newRunnable(){publicvoidrun(){outputView.setText(str);}};handler.post(proc);}}
❸ Android 10(29)适配方案简要说明
Android 10(29)适配方案简要说明
1、根据Google官方文档说明,Android10引入了大量变更
官方文档: https://developer.android.google.cn/about/versions/10/highlights?hl=zh_cn
1.1、Android 10 中的隐私权变更
1.1.1重大隐私权变更
分区存储
针对外部存储的过滤视图,可提供对特定于应用的文件和媒体集合的访问权限 访问和共享外部存储中的文件的应用 使用特定于应用的目录和媒体集合目录
增强了用户对位置权限的控制力
仅限前台权限,可让用户更好地控制应用对设备位置信息的访问权限 在后台时请求访问用户位置信息的应用 确保在没有后台位置信息更新的情况下优雅降级
使用 Android 10 中引入的权限在后台获取位置信息
系统执行后台 Activity
针对从后台启动 Activity 实施了限制 不需要用户互动就启动 Activity 的应用 使用通知触发的 Activity
不可重置的硬件标识符
针对访问设备序列号和 IMEI 实施了限制 访问设备序列号或 IMEI 的应用 使用用户可以重置的标识符
无线扫描权限
访问某些 WLAN、WLAN 感知和蓝牙扫描方法需要获得精确位置权限 使用 WLAN API 和蓝牙 API 的应用 针对相关使用场景请求 ACCESS_FINE_LOCATION 权限
1.1.2更多隐私权变更
标识符和数据: 针对硬件标识符(如 IMEI、序列号、MAC 和类似数据)实施了新限制。
移除了联系人亲密程度信息
随机分配 MAC 地址
对 /proc/net 文件系统的访问权限实施了限制
对不可重置的设备标识符实施了限制
限制了对剪贴板数据的访问权限
保护 USB 设备序列号
摄像头和连接性: 针对摄像头元数据和连接 API 提供了更强大的保护措施。 对访问摄像头详情和元数据的权限实施了限制
对启用和停用 WLAN 实施了限制
对直接访问已配置的 WLAN 网络实施了限制
一些电话 API、蓝牙 API 和 WLAN API 需要精确位置权限
权限 : 针对权限模型和要求的一些变更。
限制对屏幕内容的访问
面向用户的权限检查(针对旧版应用)
身体活动识别
从界面中移除了权限组
1.2影响应用的行为变更
文档: https://developer.android.google.cn/about/versions/10/behavior-changes-all?hl=zh_cn
限制非 SDK 接口: 为了帮助确保应用的稳定性和兼容性,Android 平台开始限制应用在 Android 9(API 级别 28)中使用非 SDK 接口。Android 10 包含更新后的受限制非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。我们的目标是在限制使用非 SDK 接口之前确保有可用的公开替代方案。
手势导航: 从 Android 10 开始,用户可以在设备中启用手势导航。用户启用后,手势导航会影响设备上的所有应用,无论应用是否以 API 级别 29 为目标平台。例如,如果用户从屏幕边缘向内滑动,系统会将该手势解读为“返回”导航,除非应用针对屏幕的相应部分明确替换该手势。
NDK 方面的变更
共享对象不得包含文本重定位
Bionic 库和动态链接器路径变更
系统二进制文件/库会映射到只执行内存
安全方面的变更
TLS 1.3 默认处于启用状态
TLS 不信任使用 SHA-1 签名的证书
KeyChain 行为变更和改进
其他 TLS 和加密更改
WLAN 直连广播
在 Android 10 中,以下与 WLAN 直连相关的广播不具有粘性:
WIFI_P2P_CONNECTION_CHANGED_ACTION
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
如果的应用依赖于在注册时接收这些广播(因为其之前一直具有粘性),请在初始化时使用适当的 get() 方法获取信息。
WLAN 感知功能
Android 10 扩大了支持范围,现在可以使用 WLAN 感知数据路径轻松创建 TCP/UDP 套接字。要创建连接到 ServerSocket 的 TCP/UDP 套接字,客户端设备需要知道服务器的 IPv6 地址和端口。这在之前需要通过频外方式进行通信(例如使用 BT 或 WLAN 感知第 2 层消息传递),或者使用其他协议(例如 mDNS)通过频内方式发现。而借助 Android 10,可以将此类消息作为网络设置的一部分进行传递。
Go 设备上的 SYSTEM_ALERT_WINDOW
在 Android 10(Go 版本)设备上运行的应用无法获得 SYSTEM_ALERT_WINDOW 权限。这是因为绘制叠加层窗口会使用过多的内存,这对低内存 Android 设备的性能十分有害。
如果在搭载 Android 9 或更低版本的 Go 版设备上运行的应用获得了 SYSTEM_ALERT_WINDOW 权限,则即使设备升级到 Android 10,也会保留此权限。不过,尚不具有此权限的应用在设备升级后便无法获得此权限了。
如果 Go 设备上的应用发送具有 ACTION_MANAGE_OVERLAY_PERMISSION 操作的 intent,则系统会自动拒绝此请求,并将用户转到设置屏幕,上面会显示不允许授予此权限,原因是它会减慢设备的运行速度。如果 Go 设备上的应用调用 Settings.canDrawOverlays(),则此方法始终返回 false。同样,这些限制不适用于在设备升级到 Android 10 之前便已收到 SYSTEM_ALERT_WINDOW 权限的应用。
关于以旧版 Android 系统为目标平台的应用的警告
在搭载 Android 10 或更高版本的设备上,如果用户首次运行以 Android 5.1(API 级别 22)或更低版本为目标平台的应用,则会看到警告。如果此应用要求用户授予权限,则系统会先向用户提供调整应用权限的机会,然后才会允许此应用首次运行。
由于 Google Play 的目标 API 方面的要求,用户只有在运行最近未更新的应用时才会看到这些警告。对于通过其他商店分发的应用,我们也将于 2019 年引入类似的目标 API 方面的要求。如需详细了解这些要求,请参阅在 2019 年扩展目标 API 级别方面的要求。
移除了 SHA-2 CBC 加密套件
以下 SHA-2 CBC 加密套件已从平台中移除:
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
这些加密套件不如使用 GCM 的类似加密套件安全,并且大多数服务器要么同时支持这些加密套件的 GCM 变体和 CBC 变体,要么二者均不支持。
应用使用情况的变更
UsageStats 应用使用情况方面的改进 - 当在分屏或画中画模式下使用应用时,Android 10 现在能够使用 UsageStats 准确地跟踪应用使用情况。此外,Android 10 可以正确地跟踪免安装应用的使用情况。
按应用开启灰度模式 - Android 10 可针对各个应用设置灰度显示模式。
按应用开启干扰模式 - Android 10 可以选择性地将应用设置为“干扰模式”,此时系统会禁止显示其通知,并且不会将其显示为推荐的应用。
暂停和播放 - 在 Android 10 中,暂停的应用无法播放音频。
HTTPS 连接变更
如果在 Android 10 上运行的应用将 null 传递给 setSSLSocketFactory(),则会出现 IllegalArgumentException。在以前的版本中,将 null 传递给 setSSLSocketFactory() 与传入当前的默认 SSL 套接字工厂效果相同。
android.preference 库已弃用
从 Android 10 开始,将弃用 android.preference 库。开发者应该改为使用 AndroidX preference 库,这是 Android Jetpack 的一部分。如需获取其他有助于迁移和开发的资源,请查看经过更新的设置指南以及我们的公开示例应用和参考文档。
ZIP 文件实用程序库变更
Android 10 对 java.util.zip 软件包(用于处理 ZIP 文件)中的类进行了以下变更。这些变更会让库的行为在 Android 和使用 java.util.zip 的其他平台之间更加一致。
Inflater
在以前的版本中,如果在调用 end() 之后调用 Inflater 类中的某些方法,这些方法会抛出 IllegalStateException。在 Android 10 中,这些方法会改为抛出 NullPointerException。
ZipFile
在 Android 10 及更高版本中,如果所提供的 ZIP 文件不包含任何文件,则 ZipFile 的构造函数(采用的参数类型为 File、int 和 Charset)不会抛出 ZipException。
ZipOutputStream
在 Android 10 及更高版本中,如果 ZipOutputStream 中的 finish() 方法尝试为不包含任何文件的 ZIP 文件写入输出流,则此方法不会抛出 ZipException。
摄像头变更
很多使用摄像头的应用都会假定如果设备采用纵向配置,则物理设备也会处于纵向,正如摄像头方向中所述。在过去可以做出这样的假定,但随着可用的设备类型(例如可折叠设备)的扩展,这一情况发生了变化。针对这些设备做出这样的假定可能导致相机取景器的显示产生错误的旋转和/或缩放。
以 API 级别 24 或更高级别为目标平台的应用应该明确设置 android:resizeableActivity,并提供必要的功能来处理多窗口操作。
电池用量跟踪
从 Android 10 开始,只要在发生重大充电事件之后拔下设备电源插头,SystemHealthManager 就会重置其电池用量统计信息。一般来说,重大充电事件指的是设备电池已充满,或者设备电量从几乎耗尽变为即将充满。
在 Android 10 之前,无论何时拔下设备电源插头,无论电池电量有多微小的变化,电池用量统计信息都会重置。
Android Beam 已弃用
在 Android 10 中,我们正式弃用了 Android Beam,这是一项旧版功能,可通过近距离无线通信 (NFC) 在多个设备之间启动数据共享。我们还弃用了一些相关的 NFC API。Android Beam 仍可供需要的设备制造商合作伙伴使用,但它已不再处于积极的开发阶段。不过,Android 仍将继续支持其他的 NFC 功能和 API,并且从标签和付款中读取数据等使用场景仍将继续按预期执行。
❹ android 设备如何获取mac地址吗
获取mac地址的话,可以在命令行窗口获取,代码如下:
Android 底层是 Linux,我们还是用Linux的方法来获取:
1 cpu号:
文件在: /proc/cpuinfo
通过Adb shell 查看:
adb shell cat /proc/cpuinfo
2 mac 地址
文件路径 /sys/class/net/wlan0/address
adb shell cat /sys/class/net/wlan0/address
xx:xx:xx:xx:xx:aa
具体的实现代码为:
public static String getLocalMac() {
String mac=null;
String str = "";
try
{
Process pp = Runtime.getRuntime().exec("cat /sys/class/net/wlan0/address ");
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
for (; null != str;)
{
str = input.readLine();
if (str != null)
{
mac = str.trim();// 去空格
break;
}
}
} catch (IOException ex) {
// 赋予默认值
ex.printStackTrace();
}
return mac;
}
❺ 怎么让Android程序一直后台运行,像QQ一样不被杀死
强烈建议不要这么做,不仅仅从用户角度考虑,作为Android开发者也有责任去维护Android的生态环境。现在很多Android开发工程师,主力机居然是iPhone而不是Android设备,感到相当悲哀。
从技术角度概括一下现在普遍的防杀方法Service设置成START_STICKY,kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样通过 startForeground将进程设置为前台进程,做前台服务,优先级和前台应用一个级别,除非在系统内存非常缺,否则此进程不会被 kill双进程Service:让2个进程互相保护,其中一个Service被清理后,另外没被清理的进程可以立即重启进程QQ黑科技:在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死在已经root的设备下,修改相应的权限文件,将App伪装成系统级的应用(Android4.0系列的一个漏洞,已经确认可行)Android系统中当前进程(Process)fork出来的子进程,被系统认为是两个不同的进程。当父进程被杀死的时候,子进程仍然可以存活,并不受影响。鉴于目前提到的在Android-Service层做双守护都会失败,我们可以fork出c进程,多进程守护。死循环在那检查是否还存在,具体的思路如下(Android5.0以下可行)用C编写守护进程(即子进程),守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它。在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。联系厂商,加入白名单
❻ 怎么让Android程序一直后台运行,像QQ一样不被杀死
1、首先要保证你的程序一直在于后台运行,也就是所谓和守护程序一样,而且在任何认为kill和系统内存回收kill后,保证重启。
2、获取系统内部资源。
3、上报策略,间隔时间上报还是按月按天上报。
4、监测网络,当网络开启的时候第一时间上报数据。
5、服务器连接。
对于以上问题的解决:
1、利用广播BroadcastReceiver监听,当系统启动时启动服务service,监听的action是
android.intent.action.BOOT_COMPLETED,当服务被kill时在onDestroy()再次启动服务,在
onStartCommand()中 设置 flags = START_STICKY;return
super.onStartCommand(intent, flags, startId),保证服务重启。
2、利用getPackageManager(),getInstalledPackages(),getApplicationInfo()来获取系统安装数据。
3、上报策略可以每天(时间间隔24小时),但是不是很准确,一般按日上报不做时间间隔这样个人认为比较准确。
4、检测开启网络上报数据,还是利用广播BroadcastReceiver监听,监听action为android.net.conn.CONNECTIVITY_CHANGE,当发现网络开启时就触发数据上报。
5、服务器连接,如果你了解java熟悉java企业级开发,那么你对httpclient并不陌生,很幸运的是android sdk已经集成了httpclient,那我们服务器连接首选它了。
以上是我做的解决方案,你是否有更好的替代品,希望我只是抛了块砖头,后面你继续。。。。
service被系统异常kill掉后回重启。有以下值:
onStartCommand有三种返回值:
START_STICKY:sticky的意思是“粘性的”。使用这个返回值时,我们启动的服务跟应用程序”粘”在一起,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务。当再次启动服务时,传入的第一个参数将为null;
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。