如何获取 Android 设备的CPU核数,时钟频率以及内存大小

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何获取 Android 设备的CPU核数,时钟频率以及内存大小相关的知识,希望对你有一定的参考价值。

获取 CPU 核数
Linux 中的设备都是以文件的形式存在,CPU 也不例外,因此 CPU 的文件个数就等价与核数。
android 的 CPU 设备文件位于/sys/devices/system/cpu/目录,文件名的的格式为cpu\\d+。
root@generic_x86_64:/sys/devices/system/cpu # ls cpu0 cpufreq
cpuidle
kernel_max
modalias
offline
online
possible
power
present
uevent
统计一下文件个数便可以获得 CPU 核数。
public static int getNumberOfCPUCores()
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
// Gingerbread doesn\'t support giving a single application access to both cores, but a
// handful of devices (Atrix 4G and Droid X2 for example) were released with a dual-core
// chipset and Gingerbread; that can let an app in the background run without impacting
// the foreground application. But for our purposes, it makes them single core.
return 1;

int cores;
try
cores = new File(“/sys/devices/system/cpu/”)。listFiles(CPU_FILTER)。length;
catch (SecurityException e)
cores = DEVICEINFO_UNKNOWN;
catch (NullPointerException e)
cores = DEVICEINFO_UNKNOWN;

return cores;

private static final FileFilter CPU_FILTER = new FileFilter()
@Override
public boolean accept(File pathname)
String path = pathname.getName();
//regex is slow, so checking char by char.
if (path.startsWith(“cpu”))
for (int i = 3; i < path.length(); i++)
if (path.charAt(i) < \'0\' path.charAt(i) > \'9‘)
return false;


return true;

return false;

;
获取时钟频率
获取时钟频率需要读取系统文件 -/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq或者/proc/cpuinfo。
Android 模拟器中并没有cpuinfo_max_freq文件,因此只能读取/proc/cpuinfo。
/proc/cpuinfo包含了很多 cpu 数据。
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 70
model name : Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
stepping : 1
cpu MHz : 0.000
cache size : 1024 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 4
wp : yes
代码如下:
public static int getCPUMaxFreqKHz()
int maxFreq = DEVICEINFO_UNKNOWN;
try
for (int i = 0; i < getNumberOfCPUCores(); i++)
String filename =
“/sys/devices/system/cpu/cpu” + i + “/cpufreq/cpuinfo_max_freq”;
File cpuInfoMaxFreqFile = new File(filename);
if (cpuInfoMaxFreqFile.exists())
byte[] buffer = new byte[128];
FileInputStream stream = new FileInputStream(cpuInfoMaxFreqFile);
try
stream.read(buffer);
int endIndex = 0;
//Trim the first number out of the byte buffer.
while (buffer[endIndex] >= \'0\' && buffer[endIndex] <= \'9\'
&& endIndex < buffer.length) endIndex++;
String str = new String(buffer, 0, endIndex);
Integer freqBound = Integer.parseInt(str);
if (freqBound > maxFreq) maxFreq = freqBound;
catch (NumberFormatException e)
//Fall through and use /proc/cpuinfo.
finally
stream.close();



if (maxFreq == DEVICEINFO_UNKNOWN)
FileInputStream stream = new FileInputStream(“/proc/cpuinfo”);
try
int freqBound = parseFileForValue(“cpu MHz”, stream);
freqBound *= 1000; //MHz -> kHz
if (freqBound > maxFreq) maxFreq = freqBound;
finally
stream.close();


catch (IOException e)
maxFreq = DEVICEINFO_UNKNOWN; //Fall through and return unknown.

return maxFreq;

获取内存大小
如果 SDK 版本大于等于JELLY_BEAN,可以通过ActivityManager来获取内从大小。
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
ActivityManager am = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE);
am.getMemoryInfo(memInfo);
如果版本低于JELLY_BEAN,则只能读取系统文件了。
FileInputStream stream = new FileInputStream(“/proc/meminfo”);
totalMem = parseFileForValue(“MemTotal”, stream);
完整代码如下:
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static long getTotalMemory(Context c)
// memInfo.totalMem not supported in pre-Jelly Bean APIs.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
ActivityManager am = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE);
am.getMemoryInfo(memInfo);
if (memInfo != null)
return memInfo.totalMem;
else
return DEVICEINFO_UNKNOWN;

else
long totalMem = DEVICEINFO_UNKNOWN;
try
FileInputStream stream = new FileInputStream(“/proc/meminfo”);
try
totalMem = parseFileForValue(“MemTotal”, stream);
totalMem *= 1024;
finally
stream.close();

catch (IOException e)

return totalMem;

参考技术A 参考这篇博文:http://www.jianshu.com/p/f7add443cd32

Android 后台任务执行

参考技术A 参考:
手机休眠引发的“血案”

使设备保持唤醒

目的为了后台能够执行定时任务,避免因为设备息屏等操作导致CPU进入睡眠状态,定时任务被暂停,这就需要能够唤醒CPU,使CPU能够起来工作

具有唤醒CPU功能, 唤醒CPU与唤醒屏幕非同一功能。

AlarmManager是安卓系统封装的用于管理RTC 模块,RTC(实时时钟)是一个独立的硬件时钟,可以在CPU休眠时正常运行,在预设的时间到达时,通过中断唤醒CPU。这意味着,如果我们用AlarmManager来定时执行任务,CPU可以正常的休眠,只有在需要运行任务时醒来一段很短的时间。

AlarmManager 定时任务测试:

MI8 UD:

测试1: 创建一个 Service, Service 中启动一个 AlarmManager 定时任务
息屏后会继续打印Log,但息屏超过1min 后,log 停止输出:

测试2: 创建一个前台通知Service
Service + StartForground + 前台通知 方式,
MI8 UD 息屏后仍继续打印log.

MI 8 + MI 10 经过测试,在长时间息屏状态下, AlarmManager 也会存在不工作情况。

另外,设备处于低电耗模式下, AlarmManager 会停止工作或延迟工作,解决办法: AlarmManager 利弊

手机长时间不操作,CPU 就会进入睡眠状态,会导致 Timer 中的定时任务无法正常运行。

息屏后,TimerTask 停止工作,再次亮屏后,继续工作

同样会由于息屏导致CPU睡眠, Handler 停止工作

太“重”了,使用起来。 影响设备耗电量。

WorkManager 也可以运行后台任务,用于在APP进程被kill后,系统依然可以运行的任务,不要用于APP被杀后,后台服务即停止的任务。

总结:

Timer并不太适用于那些需要长期在后台运行的定时任务。为了能让电池更加耐用,每种手机都会有自己的休眠策略,Android 手机就会在长时间不操作的情况下自动让 CPU 进入到睡眠状态,这就有可能导致 Timer 中的定时任务无法正常运行。

Alarm具有唤醒 CPU 的功能,即可以保证每次需要执行定时任务的时候 CPU 都能正常工作。

AlarmManager 定时任务最小间隔5S, 如何设置间隔 < 5s, 也是按照 5s 间隔执行。

Android DozeMode

以上是关于如何获取 Android 设备的CPU核数,时钟频率以及内存大小的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 Android 设备的CPU核数时钟频率以及内存大小

在 Android 设备上以编程方式获取 CPU 时钟速度?

android获取cpu核数

时钟频率

什么是时钟?什么是CPU时钟?什么是时钟脉冲?

Android 后台任务执行