mobile/android/base/SysInfo.java.in
author Richard Newman <rnewman@mozilla.com>
Wed, 22 May 2013 11:26:46 -0700
changeset 138594 638cbe677011f67986467d5b30d60cc8d1beb1a0
parent 138593 624e976d35f090e80b0ee65f17e60858c0832eeb
child 144277 4a2217e8071464f2a80dbe4a6e091f8a8657db7c
permissions -rw-r--r--
Bug 875000 - Only attempt to tweak StrictMode on API 9+. r=trivial (bustage), a=lsblakk

#filter substitution
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.gecko;

import android.os.StrictMode;
import android.util.Log;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A collection of system info values, broadly mirroring a subset of
 * nsSystemInfo. See also the constants in AppConstants, which reflect
 * much of nsIXULAppInfo.
 */
public final class SysInfo {
    private static final String LOG_TAG = "GeckoSysInfo";

    // We don't mind an instant of possible duplicate work, we only wish to
    // avoid inconsistency, so we don't bother with synchronization for
    // these.
    private static volatile int cpuCount = -1;
    private static volatile int totalRAM = -1;

      /**
       * Get the number of cores on the device.
       *
       * We can't use a nice tidy API call, because they're all wrong:
       *
       * <http://stackoverflow.com/questions/7962155/how-can-you-detect-a-dual-core-
       * cpu-on-an-android-device-from-code>
       *
       * This method is based on that code.
       *
       * @return the number of CPU cores, or 1 if the number could not be
       *         determined.
       */
    public static int getCPUCount() {
        if (cpuCount > 0) {
            return cpuCount;
        }

        if (android.os.Build.VERSION.SDK_INT < 9) {
            return readCPUCount();
        }

        // Avoid a strict mode warning... but only on devices that have StrictMode.
        StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
        try {
            return readCPUCount();
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    }

    private static int readCPUCount() {
        class CpuFilter implements FileFilter {
            @Override
            public boolean accept(File pathname) {
                return Pattern.matches("cpu[0-9]+", pathname.getName());
            }
        }
        try {
            final File dir = new File("/sys/devices/system/cpu/");
            return cpuCount = dir.listFiles(new CpuFilter()).length;
        } catch (Exception e) {
            Log.w(LOG_TAG, "Assuming 1 CPU; got exception.", e);
            return cpuCount = 1;
        }
    }

    /**
     * Fetch the total memory of the device in MB by parsing /proc/meminfo.
     * 
     * Of course, Android doesn't have a neat and tidy way to find total
     * RAM, so we do it by parsing /proc/meminfo.
     *
     * @return 0 if a problem occurred, or memory size in MB.
     */
    public static int getMemSize() {
        if (totalRAM >= 0) {
            return totalRAM;
        }

        try {
            RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
            try {
                // MemTotal will be one of the first three lines.
                int i = 0;
                String memTotal = null;
                while (i++ < 3) {
                    memTotal = reader.readLine();
                    if (memTotal == null ||
                        memTotal.startsWith("MemTotal: ")) {
                        break;
                    }
                    memTotal = null;
                }

                if (memTotal == null) {
                    return totalRAM = 0;
                }

                // Parse a line like this:
                // MemTotal: 1605324 kB
                Matcher m = Pattern.compile("^MemTotal:\\s+([0-9]+) kB\\s*$")
                                   .matcher(memTotal);
                if (m.matches()) {
                    String kb = m.group(1);
                    if (kb != null) {
                        return totalRAM = (Integer.parseInt(kb) / 1024);
                    }
                }

                Log.w(LOG_TAG, "Got unexpected MemTotal line: " + memTotal);
                return totalRAM = 0;
              } finally {
                  reader.close();
              }
          } catch (FileNotFoundException f) {
              return totalRAM = 0;
          } catch (IOException e) {
              return totalRAM = 0;
          }
    }

    /**
     * @return the SDK version supported by this device, such as '16'.
     */
    public static int getVersion() {
        return android.os.Build.VERSION.SDK_INT;
    }

    /**
     * @return the release version string, such as "4.1.2".
     */
    public static String getReleaseVersion() {
        return android.os.Build.VERSION.RELEASE;
    }

    /**
     * @return the device manufacturer, such as "HTC".
     */
    public static String getManufacturer() {
        return android.os.Build.MANUFACTURER;
    }

    /**
     * @return the device name, such as "HTC One".
     */
    public static String getDevice() {
        // No, not android.os.Build.DEVICE.
        return android.os.Build.MODEL;
    }

    /**
     * @return the Android "hardware" identifier, such as "m7".
     */
    public static String getHardware() {
        return android.os.Build.HARDWARE;
    }

    /**
     * @return the system OS name. Hardcoded to "Android".
     */
    public static String getName() {
        // We deliberately differ from PR_SI_SYSNAME, which is "Linux".
        return "Android";
    }

    /**
     * @return the architecture string, excluding ABI.
     */
    public static String getArch() {
        return "@CPU_ARCH@";   // "arm"
    }

    /**
     * @return the Android architecture string, including ABI.
     */
    public static String getArchABI() {
        // Android likes to include the ABI, too ("armeabiv7"), so we
        // differ to add value.
        return android.os.Build.CPU_ABI;
    }
}