package org.hwbot.prime.service; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.hwbot.api.bench.dto.DeviceInfoDTO; import org.hwbot.bench.model.Device; import org.hwbot.bench.model.Hardware; import org.hwbot.bench.model.Memory; import org.hwbot.bench.model.Processor; import org.hwbot.bench.prime.HardwareService; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.os.Build; import android.util.Log; import android.widget.TextSwitcher; public class AndroidHardwareService implements HardwareService, SensorEventListener, Runnable { protected static AndroidHardwareService service; protected DeviceInfoDTO deviceInfo; public static String OS = System.getProperty("os.name").toLowerCase(); private float temperature; private TextSwitcher temperatureLabel; private ScheduledExecutorService monitorThread; private int loadTemperature; private int idleTemperature = Integer.MAX_VALUE; private int maxProcessorFrequency; private AndroidHardwareService() { } public static AndroidHardwareService getInstance() { if (service == null) { service = new AndroidHardwareService(); } return service; } public String getProcessorInfo() { String processor; Log.i(this.getClass().getName(), "BOARD: " + Build.BOARD); Log.i(this.getClass().getName(), "BRAND: " + Build.BRAND); Log.i(this.getClass().getName(), "DEVICE: " + Build.DEVICE); Log.i(this.getClass().getName(), "DISPLAY: " + Build.DISPLAY); Log.i(this.getClass().getName(), "HARDWARE: " + Build.HARDWARE); Log.i(this.getClass().getName(), "TYPE: " + Build.TYPE); Log.i(this.getClass().getName(), "PRODUCT: " + Build.PRODUCT); Log.i(this.getClass().getName(), "MODEL: " + Build.MODEL); return Build.MODEL; } public int getProcessorSpeed() { String fileContents = getFileContents("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"); int maxFreqMHz = Integer.parseInt(fileContents) / 1000; Log.i(this.getClass().getSimpleName(), "Max freq: " + maxFreqMHz + " MHz"); return maxFreqMHz; } public int getMaxRecordedProcessorSpeed() { return this.maxProcessorFrequency; } public String execRuntime(String... strings) { Process proc = null; int inBuffer, errBuffer; int result = 0; StringBuffer outputReport = new StringBuffer(); StringBuffer errorBuffer = new StringBuffer(); try { proc = Runtime.getRuntime().exec(strings); } catch (IOException e) { return ""; } try { result = proc.waitFor(); } catch (InterruptedException e) { return ""; } if (proc != null && null != proc.getInputStream()) { InputStream is = proc.getInputStream(); InputStream es = proc.getErrorStream(); OutputStream os = proc.getOutputStream(); try { while ((inBuffer = is.read()) != -1) { outputReport.append((char) inBuffer); } while ((errBuffer = es.read()) != -1) { errorBuffer.append((char) errBuffer); } } catch (IOException e) { e.printStackTrace(); System.err.println("error using cpuid"); return ""; } try { is.close(); is = null; es.close(); es = null; os.close(); os = null; } catch (IOException e) { e.printStackTrace(); return ""; } // try { // proc.destroy(); // } catch (Exception e) { // // } proc = null; } if (errorBuffer.length() > 0) { System.err.println("could not finish execution because of error(s)."); System.err.println("*** Error : " + errorBuffer.toString()); return ""; } return outputReport.toString(); } public String getDeviceName() { return Build.MODEL; } public String getSocName() { return Build.BOARD; } public String getDeviceVendor() { return Build.BRAND; } @Override public Float getProcessorTemperature() { return temperature; } @Override public Hardware gatherHardwareInfo() { Processor processor = gatherProcessorInfo(); Memory memory = gatherMemoryInfo(); Device device = gatherDeviceInfo(); Hardware hardware = new Hardware(); hardware.setProcessor(processor); hardware.setMemory(memory); hardware.setDevice(device); return hardware; } private Device gatherDeviceInfo() { Device device = new Device(); device.setDeviceName(Build.MODEL); device.setSocName(Build.BOARD); device.setDeviceVendor(Build.MANUFACTURER); return device; } private Memory gatherMemoryInfo() { Memory memory = new Memory(); memory.setTotalSize(((int) getMemorySizeInBytes() / 1024 / 1024)); return memory; } private int getMemorySizeInBytes() { String fileContents = getFileContents("/proc/meminfo"); Log.i("memory: ", fileContents); return 0; } private Processor gatherProcessorInfo() { Processor processor = new Processor(); processor.setCoreClock((float) getProcessorSpeed()); processor.setName(getProcessorInfo()); processor.setEffectiveCores(getNumberOfProcessorCores()); processor.setIdleTemp(getProcessorTemperature()); return processor; } private int getNumberOfProcessorCores() { return getNumCores(); } @Override public Integer getAvailableProcessors() { return getNumberOfProcessorCores(); } public static String getFileContents(String file) { RandomAccessFile reader = null; String load = null; try { reader = new RandomAccessFile(file, "r"); load = reader.readLine(); } catch (IOException ex) { // Log.w("io error", ex.getMessage()); // ex.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { } } } return load; } /** * Gets the number of cores available in this device, across all processors. Requires: Ability to peruse the filesystem at "/sys/devices/system/cpu" * * @return The number of cores, or 1 if failed to get result */ private int getNumCores() { // Private Class to display only CPU devices in the directory listing class CpuFilter implements FileFilter { @Override public boolean accept(File pathname) { // Check if filename is "cpu", followed by a single digit number if (Pattern.matches("cpu[0-9]+", pathname.getName())) { return true; } return false; } } try { // Get directory containing CPU info File dir = new File("/sys/devices/system/cpu/"); // Filter to only list the devices we care about File[] files = dir.listFiles(new CpuFilter()); // Return the number of cores (virtual CPU devices) return files.length; } catch (Exception e) { // Default to return 1 core return 1; } } @Override public void onSensorChanged(SensorEvent event) { Log.i("sensor", "" + event.values); temperature = event.values[event.values.length - 1]; if (this.temperatureLabel != null) { this.temperatureLabel.setText(String.format(Locale.ENGLISH, "%.0f °C", temperature)); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { Log.i("sensor", "accuracy: " + accuracy); } // @Override // protected void onResume() { // super.onResume(); // mSensorManager.registerListener(this, mTempSensor, SensorManager.SENSOR_DELAY_NORMAL); // } // // @Override // protected void onPause() { // super.onPause(); // mSensorManager.unregisterListener(this); // } public void setDeviceInfo(DeviceInfoDTO deviceInfo) { this.deviceInfo = deviceInfo; } public DeviceInfoDTO getDeviceInfo() { if (deviceInfo == null){ // build basic info deviceInfo = new DeviceInfoDTO(null, Build.MODEL, null, null, null, null, null, null, null); } return deviceInfo; } public int getProcessorCores() { return getNumCores(); } public int getLoadTemperature() { return this.loadTemperature; } public int getIdleTemperature() { return this.idleTemperature; } int maxFreq0 = 0; public void restartMonitor() { monitorThread = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { public Thread newThread(Runnable runnable) { Thread thread = new Thread(runnable); thread.setPriority(Thread.MIN_PRIORITY); thread.setName("monitor"); thread.setDaemon(false); return thread; } }); } public void stopMonitorCpuFrequency() { try { if (monitorThread != null) { monitorThread.shutdownNow(); monitorThread = null; } } catch (Exception e) { e.printStackTrace(); } } public void startMonitorCpuFrequency() { try { if (monitorThread == null) { restartMonitor(); } monitorThread.scheduleAtFixedRate(this, 0, 500, TimeUnit.MILLISECONDS); } catch (Exception e) { e.printStackTrace(); } } private Map<Integer, TextSwitcher> cpuFreqMonitors = new HashMap<>(); public void monitorCpuFrequency(final int core, final TextSwitcher textSwitcher) { cpuFreqMonitors.put(core, textSwitcher); // initialize Log.i(this.getClass().getSimpleName(), "Adding monitor for core " + core); String curFreq = getFileContents("/sys/devices/system/cpu/cpu" + core + "/cpufreq/scaling_cur_freq"); if (curFreq != null) { if (NumberUtils.isDigits(curFreq)) { int mhz = Integer.parseInt(curFreq) / 1000; // Log.i(this.getClass().getSimpleName(), "Progress MHz: " + mhz); textSwitcher.setText(mhz + " MHz"); } else { textSwitcher.setText("down"); } } } public void monitorTemperature(TextSwitcher temperatureLabel) { this.temperatureLabel = temperatureLabel; } @Override public void run() { try { Set<Integer> cores = cpuFreqMonitors.keySet(); for (Integer core : cores) { TextSwitcher textSwitcher = cpuFreqMonitors.get(core); String fileContents = getFileContents("/sys/devices/system/cpu/cpu" + core + "/cpufreq/scaling_cur_freq"); if (NumberUtils.isDigits(fileContents)) { int mhz = Integer.parseInt(fileContents) / 1000; this.maxProcessorFrequency = Math.max(this.maxProcessorFrequency, mhz); textSwitcher.setText(mhz + " MHz"); } else { textSwitcher.setText("down"); } } if (this.temperatureLabel != null) { String fileContents = getFileContents("/sys/class/thermal/thermal_zone0/temp"); if (NumberUtils.isDigits(fileContents)) { int celcius = Integer.parseInt(fileContents); if (celcius > 150) { celcius /= 1000; } if (celcius < -200 || celcius > 150) { this.temperatureLabel.setText("out of range: " + celcius + " ºC"); } else { this.idleTemperature = Math.min(this.idleTemperature, celcius); this.loadTemperature = Math.max(this.loadTemperature, celcius); this.temperatureLabel.setText(celcius + " ºC"); } } else { this.temperatureLabel.setText("not available"); } } } catch (Exception e) { Log.e(this.getClass().getSimpleName(), e.getMessage()); e.printStackTrace(); } } public String getKernel() { return getFileContents("/proc/version"); } public String getOsBuild() { return Build.VERSION.RELEASE; } public String getOsDebugInfo() { return execRuntime("getprop"); } public String getHardwareFromCpuInfo() { RandomAccessFile reader = null; String info = null; try { reader = new RandomAccessFile(new File("/proc/cpuinfo"), "r"); String line = null; do { line = reader.readLine(); if (line != null && line.startsWith("Hardware")) { String hardware = StringUtils.substringAfter(line, ":").trim(); Log.i(this.getClass().getSimpleName(), "Hardware: " + hardware); info = hardware; break; } } while (line != null); } catch (IOException ex) { // Log.w("io error", ex.getMessage()); // ex.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { } } } return info != null ? info : "unknown"; } }