2011年9月26日月曜日

電力消費量計算のための基礎データ

Androidでは、power_profile.xmlに、CPUや無線利用時の電力消費量を記述することになっている。これへのアクセス方法はAPIとして公開にはなっていないが、com.android.internal.os.PowerProfileにアクセスすることで取得できる。

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.Context;
import android.util.Log;

public class PowerProfile {
 double none, cpuidle, cpuawake, wifiscan, wifion, wifiactive, gpson;
 double bluetoothon, bluetoothactive, bluetoothat, screenon, screenfull;
 double radioscanning, radioactive, dspaudio, dspvideo, batterycapacity;
 double[] cpuspeeds, cpuactives, radioon;
 String TAG = "PowerProfile";
 public PowerProfile(Context context) {
  try {
   Class bs = context.getClassLoader().loadClass("android.os.BatteryStats");
   Field f = bs.getDeclaredField("NUM_SIGNAL_STRENGTH_BINS");
   int bins = (Integer)f.get(null);
   radioon = new double[bins];
   Log.v(TAG, "NUM_SIGNAL_STRENGTH_BINS=" + bins);
   Class pp = context.getClassLoader().loadClass("com.android.internal.os.PowerProfile");
   Constructor ppconst = pp.getDeclaredConstructor(Context.class);
   Object ppobj = ppconst.newInstance(context);
   none = getAveragePower(POWER_NONE, pp, ppobj);
   cpuidle = getAveragePower(POWER_CPU_IDLE, pp, ppobj);
   cpuawake = getAveragePower(POWER_CPU_AWAKE, pp, ppobj);
   wifiscan = getAveragePower(POWER_WIFI_SCAN, pp, ppobj);
   wifion = getAveragePower(POWER_WIFI_ON, pp, ppobj);
   wifiactive = getAveragePower(POWER_WIFI_ACTIVE, pp, ppobj);
   gpson = getAveragePower(POWER_GPS_ON, pp, ppobj);
   bluetoothon = getAveragePower(POWER_BLUETOOTH_ON, pp, ppobj);
   bluetoothactive = getAveragePower(POWER_BLUETOOTH_ACTIVE, pp, ppobj);
   bluetoothat = getAveragePower(POWER_BLUETOOTH_AT_CMD, pp, ppobj);
   screenon = getAveragePower(POWER_SCREEN_ON, pp, ppobj);
   screenfull = getAveragePower(POWER_SCREEN_FULL, pp, ppobj);
   radioscanning = getAveragePower(POWER_RADIO_SCANNING, pp, ppobj);
   radioactive = getAveragePower(POWER_RADIO_ACTIVE, pp, ppobj);
   dspaudio = getAveragePower(POWER_AUDIO, pp, ppobj);
   dspvideo = getAveragePower(POWER_VIDEO, pp, ppobj);
   batterycapacity = getAveragePower(POWER_BATTERY_CAPACITY, pp, ppobj);
   for (int i = 0; i < radioon.length; i++) {
    radioon[i] = getAveragePower(POWER_RADIO_ON, i, pp, ppobj);
   }
   int numSpeedSteps = getNumSpeedSteps(pp, ppobj);
   cpuspeeds = new double[numSpeedSteps];
   for (int i = 0; i < cpuspeeds.length; i++) {
    cpuspeeds[i] = getAveragePower(POWER_CPU_SPEEDS, i, pp, ppobj);
   }
   cpuactives = new double[numSpeedSteps];
   for (int i = 0; i < cpuactives.length; i++) {
    cpuactives[i] = getAveragePower(POWER_CPU_ACTIVE, i, pp, ppobj);
   }
  } catch (Exception e) {
   e.printStackTrace();
   Log.e("PowerProfile", e.getLocalizedMessage());
  }
 }
 private double getAveragePower(String type, Class pp, Object ppobj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  Method ppm = pp.getDeclaredMethod("getAveragePower", String.class);
  double value = (Double)ppm.invoke(ppobj, type);
  Log.v(TAG, type + "=" + value);
  return value;
 }
 private double getAveragePower(String type, int i, Class pp, Object ppobj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  Method ppm = pp.getDeclaredMethod("getAveragePower", String.class, int.class);
  double value = (Double)ppm.invoke(ppobj, type, i);
  Log.v(TAG, type + "(" + i + ")=" + value);
  return value;
 }
 private int getNumSpeedSteps(Class pp, Object ppobj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  Method ppm = pp.getDeclaredMethod("getNumSpeedSteps");
  int value = (Integer)ppm.invoke(ppobj);
  Log.v(TAG, "NumSpeedSteps" + "=" + value);
  return value;
 }
 public static final String POWER_NONE = "none";
 public static final String POWER_CPU_IDLE = "cpu.idle";
 public static final String POWER_CPU_AWAKE = "cpu.awake";
 public static final String POWER_CPU_ACTIVE = "cpu.active";
 public static final String POWER_WIFI_SCAN = "wifi.scan";
 public static final String POWER_WIFI_ON = "wifi.on";
 public static final String POWER_WIFI_ACTIVE = "wifi.active";
 public static final String POWER_GPS_ON = "gps.on";
 public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
 public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
 public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
 public static final String POWER_SCREEN_ON = "screen.on";
 public static final String POWER_RADIO_ON = "radio.on";
 public static final String POWER_RADIO_SCANNING = "radio.scanning";
 public static final String POWER_RADIO_ACTIVE = "radio.active";
 public static final String POWER_SCREEN_FULL = "screen.full";
 public static final String POWER_AUDIO = "dsp.audio";
 public static final String POWER_VIDEO = "dsp.video";
 public static final String POWER_CPU_SPEEDS = "cpu.speeds";
 public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
}

公開APIではないので将来的には変更されるだろう。なお、Nexus S(2.3.4)で動作を確認した。また、この値がデフォルトのままのものもあるようだ。そのような機種では、電力消費量が正しく表示されないだろう。

0 件のコメント:

コメントを投稿