如何獲取 Android 設備的CPU核數、時鐘頻率以及內存大小

jopen 9年前發布 | 68K 次閱讀 Android Android開發 移動開發

因項目需要,分析了一下 非死book 的開源項目 - Device Year Class

Device Year Class 的主要功能是根據 CPU核數時鐘頻率 以及 內存大小 對設備進行分級。代碼很簡單,只包含兩個類:

  • DeviceInfo-> 獲取設備參數,
  • YearClass-> 根據參數進行分級。
  • </ul>

    下表是 非死book 公司提供的分級標準,其中Year欄表示分級結果。

    </tr> </tbody>

    </tr>

    </tr>

    </tr>

    </tr>

    </tr>

    </tr>

    </tr> </tbody> </table>

    關于輸出年份的計算方法可以參考源碼,本文只把一些比較常用的功能抽取出來做一個簡要介紹。

    獲取 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; } };</pre>

    獲取時鐘頻率

    獲取時鐘頻率需要讀取系統文件 -/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;
      }
    }
    來自:http://www.jianshu.com/p/f7add443cd32

     本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
     轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
     本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
    Year Cores Clock RAM
    2008 1 528MHz 192MB
    2009 n/a 600MHz 290MB
    2010 n/a 1.0GHz 512MB
    2011 2 1.2GHz 1GB
    2012 4 1.5GHz 1.5GB
    2013 n/a 2.0GHz 2GB
    2014 n/a >2GHz >2GB
sesese色