BatteryServicepublic class BatteryService extends android.os.Binder BatteryService monitors the charging status, and charge level of the device
battery. When these values change this service broadcasts the new values
to all {@link android.content.BroadcastReceiver IntentReceivers} that are
watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
BATTERY_CHANGED} action.
The new values are stored in the Intent data and can be retrieved by
calling {@link android.content.Intent#getExtra Intent.getExtra} with the
following keys:
"scale" - int, the maximum value for the charge level
"level" - int, charge level, from 0 through "scale" inclusive
"status" - String, the current charging status.
"health" - String, the current battery health.
"present" - boolean, true if the battery is present
"icon-small" - int, suggested small icon to use for this state
"plugged" - int, 0 if the device is not plugged in; 1 if plugged
into an AC power adapter; 2 if plugged in via USB.
"voltage" - int, current battery voltage in millivolts
"temperature" - int, current battery temperature in tenths of
a degree Centigrade
"technology" - String, the type of battery installed, e.g. "Li-ion" |
Fields Summary |
---|
private static final String | TAG | private static final boolean | LOCAL_LOGV | static final int | LOG_BATTERY_LEVEL | static final int | LOG_BATTERY_STATUS | static final int | LOG_BATTERY_DISCHARGE_STATUS | static final int | BATTERY_SCALE | private static final int | CRITICAL_BATTERY_LEVEL | private static final int | DUMP_MAX_LENGTH | private static final String[] | DUMPSYS_ARGS | private static final String | BATTERY_STATS_SERVICE_NAME | private static final String | DUMPSYS_DATA_PATH | private static final int | BATTERY_PLUGGED_NONE | private final android.content.Context | mContext | private final com.android.internal.app.IBatteryStats | mBatteryStats | private boolean | mAcOnline | private boolean | mUsbOnline | private int | mBatteryStatus | private int | mBatteryHealth | private boolean | mBatteryPresent | private int | mBatteryLevel | private int | mBatteryVoltage | private int | mBatteryTemperature | private String | mBatteryTechnology | private boolean | mBatteryLevelCritical | private int | mLastBatteryStatus | private int | mLastBatteryHealth | private boolean | mLastBatteryPresent | private int | mLastBatteryLevel | private int | mLastBatteryVoltage | private int | mLastBatteryTemperature | private boolean | mLastBatteryLevelCritical | private int | mPlugType | private int | mLastPlugType | private long | mDischargeStartTime | private int | mDischargeStartLevel | private android.os.UEventObserver | mUEventObserver |
Constructors Summary |
---|
public BatteryService(android.content.Context context)
mContext = context;
mBatteryStats = BatteryStatsService.getService();
mUEventObserver.startObserving("SUBSYSTEM=power_supply");
// set initial status
update();
|
Methods Summary |
---|
protected void | dump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump Battery service from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
}
synchronized (this) {
pw.println("Current Battery Service state:");
pw.println(" AC powered: " + mAcOnline);
pw.println(" USB powered: " + mUsbOnline);
pw.println(" status: " + mBatteryStatus);
pw.println(" health: " + mBatteryHealth);
pw.println(" present: " + mBatteryPresent);
pw.println(" level: " + mBatteryLevel);
pw.println(" scale: " + BATTERY_SCALE);
pw.println(" voltage:" + mBatteryVoltage);
pw.println(" temperature: " + mBatteryTemperature);
pw.println(" technology: " + mBatteryTechnology);
}
| final int | getBatteryLevel()
// returns battery level as a percentage
return mBatteryLevel;
| private final int | getIcon(int level)
if (mBatteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
} else if (mBatteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING ||
mBatteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING ||
mBatteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
return com.android.internal.R.drawable.stat_sys_battery;
} else {
return com.android.internal.R.drawable.stat_sys_battery_unknown;
}
| final int | getPlugType()
return mPlugType;
| final boolean | isPowered()
// assume we are powered if battery state is unknown so the "stay on while plugged in" option will work.
return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN);
| final boolean | isPowered(int plugTypeSet)
// assume we are powered if battery state is unknown so
// the "stay on while plugged in" option will work.
if (mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
return true;
}
if (plugTypeSet == 0) {
return false;
}
int plugTypeBit = 0;
if (mAcOnline) {
plugTypeBit |= BatteryManager.BATTERY_PLUGGED_AC;
}
if (mUsbOnline) {
plugTypeBit |= BatteryManager.BATTERY_PLUGGED_USB;
}
return (plugTypeSet & plugTypeBit) != 0;
| private final void | logBatteryStats()
IBinder batteryInfoService = ServiceManager.getService(BATTERY_STATS_SERVICE_NAME);
if (batteryInfoService != null) {
byte[] buffer = new byte[DUMP_MAX_LENGTH];
File dumpFile = null;
FileOutputStream dumpStream = null;
try {
// dump the service to a file
dumpFile = new File(DUMPSYS_DATA_PATH + BATTERY_STATS_SERVICE_NAME + ".dump");
dumpStream = new FileOutputStream(dumpFile);
batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
dumpStream.getFD().sync();
// read dumped file above into buffer truncated to DUMP_MAX_LENGTH
// and insert into events table.
int length = (int) Math.min(dumpFile.length(), DUMP_MAX_LENGTH);
FileInputStream fileInputStream = new FileInputStream(dumpFile);
int nread = fileInputStream.read(buffer, 0, length);
if (nread > 0) {
Checkin.logEvent(mContext.getContentResolver(),
Checkin.Events.Tag.BATTERY_DISCHARGE_INFO,
new String(buffer, 0, nread));
if (LOCAL_LOGV) Log.v(TAG, "dumped " + nread + "b from " +
batteryInfoService + "to log");
if (LOCAL_LOGV) Log.v(TAG, "actual dump:" + new String(buffer, 0, nread));
}
} catch (RemoteException e) {
Log.e(TAG, "failed to dump service '" + BATTERY_STATS_SERVICE_NAME +
"':" + e);
} catch (IOException e) {
Log.e(TAG, "failed to write dumpsys file: " + e);
} finally {
// make sure we clean up
if (dumpStream != null) {
try {
dumpStream.close();
} catch (IOException e) {
Log.e(TAG, "failed to close dumpsys output stream");
}
}
if (dumpFile != null && !dumpFile.delete()) {
Log.e(TAG, "failed to delete temporary dumpsys file: "
+ dumpFile.getAbsolutePath());
}
}
}
| private final void | logOutlier(long duration)
ContentResolver cr = mContext.getContentResolver();
String dischargeThresholdString = Settings.Gservices.getString(cr,
Settings.Gservices.BATTERY_DISCHARGE_THRESHOLD);
String durationThresholdString = Settings.Gservices.getString(cr,
Settings.Gservices.BATTERY_DISCHARGE_DURATION_THRESHOLD);
if (dischargeThresholdString != null && durationThresholdString != null) {
try {
long durationThreshold = Long.parseLong(durationThresholdString);
int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
if (duration <= durationThreshold &&
mDischargeStartLevel - mBatteryLevel >= dischargeThreshold) {
// If the discharge cycle is bad enough we want to know about it.
logBatteryStats();
}
if (LOCAL_LOGV) Log.v(TAG, "duration threshold: " + durationThreshold +
" discharge threshold: " + dischargeThreshold);
if (LOCAL_LOGV) Log.v(TAG, "duration: " + duration + " discharge: " +
(mDischargeStartLevel - mBatteryLevel));
} catch (NumberFormatException e) {
Log.e(TAG, "Invalid DischargeThresholds GService string: " +
durationThresholdString + " or " + dischargeThresholdString);
return;
}
}
| private native void | native_update()
| private final void | sendIntent()
// Pack up the values and broadcast them to everyone
Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
try {
mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE, mBatteryLevel);
} catch (RemoteException e) {
// Should never happen.
}
int icon = getIcon(mBatteryLevel);
intent.putExtra("status", mBatteryStatus);
intent.putExtra("health", mBatteryHealth);
intent.putExtra("present", mBatteryPresent);
intent.putExtra("level", mBatteryLevel);
intent.putExtra("scale", BATTERY_SCALE);
intent.putExtra("icon-small", icon);
intent.putExtra("plugged", mPlugType);
intent.putExtra("voltage", mBatteryVoltage);
intent.putExtra("temperature", mBatteryTemperature);
intent.putExtra("technology", mBatteryTechnology);
if (false) {
Log.d(TAG, "updateBattery level:" + mBatteryLevel +
" scale:" + BATTERY_SCALE + " status:" + mBatteryStatus +
" health:" + mBatteryHealth + " present:" + mBatteryPresent +
" voltage: " + mBatteryVoltage +
" temperature: " + mBatteryTemperature +
" technology: " + mBatteryTechnology +
" AC powered:" + mAcOnline + " USB powered:" + mUsbOnline +
" icon:" + icon );
}
ActivityManagerNative.broadcastStickyIntent(intent, null);
| private final synchronized void | update()
native_update();
boolean logOutlier = false;
long dischargeDuration = 0;
mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
if (mAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
} else if (mUsbOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
} else {
mPlugType = BATTERY_PLUGGED_NONE;
}
if (mBatteryStatus != mLastBatteryStatus ||
mBatteryHealth != mLastBatteryHealth ||
mBatteryPresent != mLastBatteryPresent ||
mBatteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
mBatteryVoltage != mLastBatteryVoltage ||
mBatteryTemperature != mLastBatteryTemperature) {
if (mPlugType != mLastPlugType) {
if (mLastPlugType == BATTERY_PLUGGED_NONE) {
// discharging -> charging
// There's no value in this data unless we've discharged at least once and the
// battery level has changed; so don't log until it does.
if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryLevel) {
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
EventLog.writeEvent(LOG_BATTERY_DISCHARGE_STATUS, dischargeDuration,
mDischargeStartLevel, mBatteryLevel);
// make sure we see a discharge event before logging again
mDischargeStartTime = 0;
}
} else if (mPlugType == BATTERY_PLUGGED_NONE) {
// charging -> discharging or we just powered up
mDischargeStartTime = SystemClock.elapsedRealtime();
mDischargeStartLevel = mBatteryLevel;
}
}
if (mBatteryStatus != mLastBatteryStatus ||
mBatteryHealth != mLastBatteryHealth ||
mBatteryPresent != mLastBatteryPresent ||
mPlugType != mLastPlugType) {
EventLog.writeEvent(LOG_BATTERY_STATUS,
mBatteryStatus, mBatteryHealth, mBatteryPresent ? 1 : 0,
mPlugType, mBatteryTechnology);
}
if (mBatteryLevel != mLastBatteryLevel ||
mBatteryVoltage != mLastBatteryVoltage ||
mBatteryTemperature != mLastBatteryTemperature) {
EventLog.writeEvent(LOG_BATTERY_LEVEL,
mBatteryLevel, mBatteryVoltage, mBatteryTemperature);
}
if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
mPlugType == BATTERY_PLUGGED_NONE) {
// We want to make sure we log discharge cycle outliers
// if the battery is about to die.
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
}
mLastBatteryStatus = mBatteryStatus;
mLastBatteryHealth = mBatteryHealth;
mLastBatteryPresent = mBatteryPresent;
mLastBatteryLevel = mBatteryLevel;
mLastPlugType = mPlugType;
mLastBatteryVoltage = mBatteryVoltage;
mLastBatteryTemperature = mBatteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
sendIntent();
// This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
logOutlier(dischargeDuration);
}
}
|
|