Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import android.app.ActivityManagerInternal;
     20 import android.database.ContentObserver;
     21 import android.os.BatteryStats;
     22 
     23 import android.os.ResultReceiver;
     24 import android.os.ShellCallback;
     25 import android.os.ShellCommand;
     26 import com.android.internal.app.IBatteryStats;
     27 import com.android.internal.util.DumpUtils;
     28 import com.android.server.am.BatteryStatsService;
     29 import com.android.server.lights.Light;
     30 import com.android.server.lights.LightsManager;
     31 
     32 import android.app.ActivityManager;
     33 import android.content.ContentResolver;
     34 import android.content.Context;
     35 import android.content.Intent;
     36 import android.content.pm.PackageManager;
     37 import android.os.BatteryManager;
     38 import android.os.BatteryManagerInternal;
     39 import android.os.BatteryProperties;
     40 import android.os.Binder;
     41 import android.os.FileUtils;
     42 import android.os.Handler;
     43 import android.os.IBatteryPropertiesListener;
     44 import android.os.IBatteryPropertiesRegistrar;
     45 import android.os.IBinder;
     46 import android.os.DropBoxManager;
     47 import android.os.RemoteException;
     48 import android.os.ServiceManager;
     49 import android.os.SystemClock;
     50 import android.os.UEventObserver;
     51 import android.os.UserHandle;
     52 import android.provider.Settings;
     53 import android.service.battery.BatteryServiceDumpProto;
     54 import android.util.EventLog;
     55 import android.util.Slog;
     56 import android.util.proto.ProtoOutputStream;
     57 
     58 import java.io.File;
     59 import java.io.FileDescriptor;
     60 import java.io.FileOutputStream;
     61 import java.io.IOException;
     62 import java.io.PrintWriter;
     63 
     64 
     65 /**
     66  * <p>BatteryService monitors the charging status, and charge level of the device
     67  * battery.  When these values change this service broadcasts the new values
     68  * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
     69  * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
     70  * BATTERY_CHANGED} action.</p>
     71  * <p>The new values are stored in the Intent data and can be retrieved by
     72  * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
     73  * following keys:</p>
     74  * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
     75  * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
     76  * <p>&quot;status&quot; - String, the current charging status.<br />
     77  * <p>&quot;health&quot; - String, the current battery health.<br />
     78  * <p>&quot;present&quot; - boolean, true if the battery is present<br />
     79  * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
     80  * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
     81  * into an AC power adapter; 2 if plugged in via USB.</p>
     82  * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
     83  * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
     84  * a degree Centigrade</p>
     85  * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
     86  *
     87  * <p>
     88  * The battery service may be called by the power manager while holding its locks so
     89  * we take care to post all outcalls into the activity manager to a handler.
     90  *
     91  * FIXME: Ideally the power manager would perform all of its calls into the battery
     92  * service asynchronously itself.
     93  * </p>
     94  */
     95 public final class BatteryService extends SystemService {
     96     private static final String TAG = BatteryService.class.getSimpleName();
     97 
     98     private static final boolean DEBUG = false;
     99 
    100     private static final int BATTERY_SCALE = 100;    // battery capacity is a percentage
    101 
    102     // Used locally for determining when to make a last ditch effort to log
    103     // discharge stats before the device dies.
    104     private int mCriticalBatteryLevel;
    105 
    106     private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
    107 
    108     private static final String DUMPSYS_DATA_PATH = "/data/system/";
    109 
    110     // This should probably be exposed in the API, though it's not critical
    111     private static final int BATTERY_PLUGGED_NONE = 0;
    112 
    113     private final Context mContext;
    114     private final IBatteryStats mBatteryStats;
    115     BinderService mBinderService;
    116     private final Handler mHandler;
    117 
    118     private final Object mLock = new Object();
    119 
    120     private BatteryProperties mBatteryProps;
    121     private final BatteryProperties mLastBatteryProps = new BatteryProperties();
    122     private boolean mBatteryLevelCritical;
    123     private int mLastBatteryStatus;
    124     private int mLastBatteryHealth;
    125     private boolean mLastBatteryPresent;
    126     private int mLastBatteryLevel;
    127     private int mLastBatteryVoltage;
    128     private int mLastBatteryTemperature;
    129     private boolean mLastBatteryLevelCritical;
    130     private int mLastMaxChargingCurrent;
    131     private int mLastMaxChargingVoltage;
    132     private int mLastChargeCounter;
    133 
    134     private int mSequence = 1;
    135 
    136     private int mInvalidCharger;
    137     private int mLastInvalidCharger;
    138 
    139     private int mLowBatteryWarningLevel;
    140     private int mLowBatteryCloseWarningLevel;
    141     private int mShutdownBatteryTemperature;
    142 
    143     private int mPlugType;
    144     private int mLastPlugType = -1; // Extra state so we can detect first run
    145 
    146     private boolean mBatteryLevelLow;
    147 
    148     private long mDischargeStartTime;
    149     private int mDischargeStartLevel;
    150 
    151     private boolean mUpdatesStopped;
    152 
    153     private Led mLed;
    154 
    155     private boolean mSentLowBatteryBroadcast = false;
    156 
    157     private ActivityManagerInternal mActivityManagerInternal;
    158 
    159     public BatteryService(Context context) {
    160         super(context);
    161 
    162         mContext = context;
    163         mHandler = new Handler(true /*async*/);
    164         mLed = new Led(context, getLocalService(LightsManager.class));
    165         mBatteryStats = BatteryStatsService.getService();
    166         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
    167 
    168         mCriticalBatteryLevel = mContext.getResources().getInteger(
    169                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
    170         mLowBatteryWarningLevel = mContext.getResources().getInteger(
    171                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
    172         mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
    173                 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
    174         mShutdownBatteryTemperature = mContext.getResources().getInteger(
    175                 com.android.internal.R.integer.config_shutdownBatteryTemperature);
    176 
    177         // watch for invalid charger messages if the invalid_charger switch exists
    178         if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
    179             UEventObserver invalidChargerObserver = new UEventObserver() {
    180                 @Override
    181                 public void onUEvent(UEvent event) {
    182                     final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
    183                     synchronized (mLock) {
    184                         if (mInvalidCharger != invalidCharger) {
    185                             mInvalidCharger = invalidCharger;
    186                         }
    187                     }
    188                 }
    189             };
    190             invalidChargerObserver.startObserving(
    191                     "DEVPATH=/devices/virtual/switch/invalid_charger");
    192         }
    193     }
    194 
    195     @Override
    196     public void onStart() {
    197         IBinder b = ServiceManager.getService("batteryproperties");
    198         final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
    199                 IBatteryPropertiesRegistrar.Stub.asInterface(b);
    200         try {
    201             batteryPropertiesRegistrar.registerListener(new BatteryListener());
    202         } catch (RemoteException e) {
    203             // Should never happen.
    204         }
    205 
    206         mBinderService = new BinderService();
    207         publishBinderService("battery", mBinderService);
    208         publishLocalService(BatteryManagerInternal.class, new LocalService());
    209     }
    210 
    211     @Override
    212     public void onBootPhase(int phase) {
    213         if (phase == PHASE_ACTIVITY_MANAGER_READY) {
    214             // check our power situation now that it is safe to display the shutdown dialog.
    215             synchronized (mLock) {
    216                 ContentObserver obs = new ContentObserver(mHandler) {
    217                     @Override
    218                     public void onChange(boolean selfChange) {
    219                         synchronized (mLock) {
    220                             updateBatteryWarningLevelLocked();
    221                         }
    222                     }
    223                 };
    224                 final ContentResolver resolver = mContext.getContentResolver();
    225                 resolver.registerContentObserver(Settings.Global.getUriFor(
    226                         Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
    227                         false, obs, UserHandle.USER_ALL);
    228                 updateBatteryWarningLevelLocked();
    229             }
    230         }
    231     }
    232 
    233     private void updateBatteryWarningLevelLocked() {
    234         final ContentResolver resolver = mContext.getContentResolver();
    235         int defWarnLevel = mContext.getResources().getInteger(
    236                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
    237         mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
    238                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
    239         if (mLowBatteryWarningLevel == 0) {
    240             mLowBatteryWarningLevel = defWarnLevel;
    241         }
    242         if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
    243             mLowBatteryWarningLevel = mCriticalBatteryLevel;
    244         }
    245         mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
    246                 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
    247         processValuesLocked(true);
    248     }
    249 
    250     private boolean isPoweredLocked(int plugTypeSet) {
    251         // assume we are powered if battery state is unknown so
    252         // the "stay on while plugged in" option will work.
    253         if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
    254             return true;
    255         }
    256         if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
    257             return true;
    258         }
    259         if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
    260             return true;
    261         }
    262         if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
    263             return true;
    264         }
    265         return false;
    266     }
    267 
    268     private boolean shouldSendBatteryLowLocked() {
    269         final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
    270         final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
    271 
    272         /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
    273          * - is just un-plugged (previously was plugged) and battery level is
    274          *   less than or equal to WARNING, or
    275          * - is not plugged and battery level falls to WARNING boundary
    276          *   (becomes <= mLowBatteryWarningLevel).
    277          */
    278         return !plugged
    279                 && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
    280                 && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
    281                 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
    282     }
    283 
    284     private void shutdownIfNoPowerLocked() {
    285         // shut down gracefully if our battery is critically low and we are not powered.
    286         // wait until the system has booted before attempting to display the shutdown dialog.
    287         if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
    288             mHandler.post(new Runnable() {
    289                 @Override
    290                 public void run() {
    291                     if (mActivityManagerInternal.isSystemReady()) {
    292                         Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
    293                         intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
    294                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    295                         mContext.startActivityAsUser(intent, UserHandle.CURRENT);
    296                     }
    297                 }
    298             });
    299         }
    300     }
    301 
    302     private void shutdownIfOverTempLocked() {
    303         // shut down gracefully if temperature is too high (> 68.0C by default)
    304         // wait until the system has booted before attempting to display the
    305         // shutdown dialog.
    306         if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {
    307             mHandler.post(new Runnable() {
    308                 @Override
    309                 public void run() {
    310                     if (mActivityManagerInternal.isSystemReady()) {
    311                         Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
    312                         intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
    313                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    314                         mContext.startActivityAsUser(intent, UserHandle.CURRENT);
    315                     }
    316                 }
    317             });
    318         }
    319     }
    320 
    321     private void update(BatteryProperties props) {
    322         synchronized (mLock) {
    323             if (!mUpdatesStopped) {
    324                 mBatteryProps = props;
    325                 // Process the new values.
    326                 processValuesLocked(false);
    327             } else {
    328                 mLastBatteryProps.set(props);
    329             }
    330         }
    331     }
    332 
    333     private void processValuesLocked(boolean force) {
    334         boolean logOutlier = false;
    335         long dischargeDuration = 0;
    336 
    337         mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
    338         if (mBatteryProps.chargerAcOnline) {
    339             mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
    340         } else if (mBatteryProps.chargerUsbOnline) {
    341             mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
    342         } else if (mBatteryProps.chargerWirelessOnline) {
    343             mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
    344         } else {
    345             mPlugType = BATTERY_PLUGGED_NONE;
    346         }
    347 
    348         if (DEBUG) {
    349             Slog.d(TAG, "Processing new values: "
    350                     + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
    351                     + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
    352                     + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
    353                     + ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent
    354                     + ", maxChargingVoltage" + mBatteryProps.maxChargingVoltage
    355                     + ", batteryStatus=" + mBatteryProps.batteryStatus
    356                     + ", batteryHealth=" + mBatteryProps.batteryHealth
    357                     + ", batteryPresent=" + mBatteryProps.batteryPresent
    358                     + ", batteryLevel=" + mBatteryProps.batteryLevel
    359                     + ", batteryTechnology=" + mBatteryProps.batteryTechnology
    360                     + ", batteryVoltage=" + mBatteryProps.batteryVoltage
    361                     + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter
    362                     + ", batteryFullCharge=" + mBatteryProps.batteryFullCharge
    363                     + ", batteryTemperature=" + mBatteryProps.batteryTemperature
    364                     + ", mBatteryLevelCritical=" + mBatteryLevelCritical
    365                     + ", mPlugType=" + mPlugType);
    366         }
    367 
    368         // Let the battery stats keep track of the current level.
    369         try {
    370             mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
    371                     mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
    372                     mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter,
    373                     mBatteryProps.batteryFullCharge);
    374         } catch (RemoteException e) {
    375             // Should never happen.
    376         }
    377 
    378         shutdownIfNoPowerLocked();
    379         shutdownIfOverTempLocked();
    380 
    381         if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
    382                 mBatteryProps.batteryHealth != mLastBatteryHealth ||
    383                 mBatteryProps.batteryPresent != mLastBatteryPresent ||
    384                 mBatteryProps.batteryLevel != mLastBatteryLevel ||
    385                 mPlugType != mLastPlugType ||
    386                 mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
    387                 mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
    388                 mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent ||
    389                 mBatteryProps.maxChargingVoltage != mLastMaxChargingVoltage ||
    390                 mBatteryProps.batteryChargeCounter != mLastChargeCounter ||
    391                 mInvalidCharger != mLastInvalidCharger)) {
    392 
    393             if (mPlugType != mLastPlugType) {
    394                 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
    395                     // discharging -> charging
    396 
    397                     // There's no value in this data unless we've discharged at least once and the
    398                     // battery level has changed; so don't log until it does.
    399                     if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
    400                         dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
    401                         logOutlier = true;
    402                         EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
    403                                 mDischargeStartLevel, mBatteryProps.batteryLevel);
    404                         // make sure we see a discharge event before logging again
    405                         mDischargeStartTime = 0;
    406                     }
    407                 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
    408                     // charging -> discharging or we just powered up
    409                     mDischargeStartTime = SystemClock.elapsedRealtime();
    410                     mDischargeStartLevel = mBatteryProps.batteryLevel;
    411                 }
    412             }
    413             if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
    414                     mBatteryProps.batteryHealth != mLastBatteryHealth ||
    415                     mBatteryProps.batteryPresent != mLastBatteryPresent ||
    416                     mPlugType != mLastPlugType) {
    417                 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
    418                         mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
    419                         mPlugType, mBatteryProps.batteryTechnology);
    420             }
    421             if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
    422                 // Don't do this just from voltage or temperature changes, that is
    423                 // too noisy.
    424                 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
    425                         mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
    426             }
    427             if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
    428                     mPlugType == BATTERY_PLUGGED_NONE) {
    429                 // We want to make sure we log discharge cycle outliers
    430                 // if the battery is about to die.
    431                 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
    432                 logOutlier = true;
    433             }
    434 
    435             if (!mBatteryLevelLow) {
    436                 // Should we now switch in to low battery mode?
    437                 if (mPlugType == BATTERY_PLUGGED_NONE
    438                         && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
    439                     mBatteryLevelLow = true;
    440                 }
    441             } else {
    442                 // Should we now switch out of low battery mode?
    443                 if (mPlugType != BATTERY_PLUGGED_NONE) {
    444                     mBatteryLevelLow = false;
    445                 } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel)  {
    446                     mBatteryLevelLow = false;
    447                 } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
    448                     // If being forced, the previous state doesn't matter, we will just
    449                     // absolutely check to see if we are now above the warning level.
    450                     mBatteryLevelLow = false;
    451                 }
    452             }
    453 
    454             mSequence++;
    455 
    456             // Separate broadcast is sent for power connected / not connected
    457             // since the standard intent will not wake any applications and some
    458             // applications may want to have smart behavior based on this.
    459             if (mPlugType != 0 && mLastPlugType == 0) {
    460                 final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
    461                 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    462                 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
    463                 mHandler.post(new Runnable() {
    464                     @Override
    465                     public void run() {
    466                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
    467                     }
    468                 });
    469             }
    470             else if (mPlugType == 0 && mLastPlugType != 0) {
    471                 final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
    472                 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    473                 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
    474                 mHandler.post(new Runnable() {
    475                     @Override
    476                     public void run() {
    477                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
    478                     }
    479                 });
    480             }
    481 
    482             if (shouldSendBatteryLowLocked()) {
    483                 mSentLowBatteryBroadcast = true;
    484                 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
    485                 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    486                 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
    487                 mHandler.post(new Runnable() {
    488                     @Override
    489                     public void run() {
    490                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
    491                     }
    492                 });
    493             } else if (mSentLowBatteryBroadcast &&
    494                     mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
    495                 mSentLowBatteryBroadcast = false;
    496                 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
    497                 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    498                 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
    499                 mHandler.post(new Runnable() {
    500                     @Override
    501                     public void run() {
    502                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
    503                     }
    504                 });
    505             }
    506 
    507             // We are doing this after sending the above broadcasts, so anything processing
    508             // them will get the new sequence number at that point.  (See for example how testing
    509             // of JobScheduler's BatteryController works.)
    510             sendIntentLocked();
    511 
    512             // Update the battery LED
    513             mLed.updateLightsLocked();
    514 
    515             // This needs to be done after sendIntent() so that we get the lastest battery stats.
    516             if (logOutlier && dischargeDuration != 0) {
    517                 logOutlierLocked(dischargeDuration);
    518             }
    519 
    520             mLastBatteryStatus = mBatteryProps.batteryStatus;
    521             mLastBatteryHealth = mBatteryProps.batteryHealth;
    522             mLastBatteryPresent = mBatteryProps.batteryPresent;
    523             mLastBatteryLevel = mBatteryProps.batteryLevel;
    524             mLastPlugType = mPlugType;
    525             mLastBatteryVoltage = mBatteryProps.batteryVoltage;
    526             mLastBatteryTemperature = mBatteryProps.batteryTemperature;
    527             mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent;
    528             mLastMaxChargingVoltage = mBatteryProps.maxChargingVoltage;
    529             mLastChargeCounter = mBatteryProps.batteryChargeCounter;
    530             mLastBatteryLevelCritical = mBatteryLevelCritical;
    531             mLastInvalidCharger = mInvalidCharger;
    532         }
    533     }
    534 
    535     private void sendIntentLocked() {
    536         //  Pack up the values and broadcast them to everyone
    537         final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
    538         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
    539                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
    540 
    541         int icon = getIconLocked(mBatteryProps.batteryLevel);
    542 
    543         intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
    544         intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
    545         intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
    546         intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
    547         intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
    548         intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
    549         intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
    550         intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
    551         intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);
    552         intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);
    553         intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);
    554         intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
    555         intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
    556         intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
    557         intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mBatteryProps.batteryChargeCounter);
    558         if (DEBUG) {
    559             Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED.  level:" + mBatteryProps.batteryLevel +
    560                     ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +
    561                     ", health:" + mBatteryProps.batteryHealth +
    562                     ", present:" + mBatteryProps.batteryPresent +
    563                     ", voltage: " + mBatteryProps.batteryVoltage +
    564                     ", temperature: " + mBatteryProps.batteryTemperature +
    565                     ", technology: " + mBatteryProps.batteryTechnology +
    566                     ", AC powered:" + mBatteryProps.chargerAcOnline +
    567                     ", USB powered:" + mBatteryProps.chargerUsbOnline +
    568                     ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +
    569                     ", icon:" + icon  + ", invalid charger:" + mInvalidCharger +
    570                     ", maxChargingCurrent:" + mBatteryProps.maxChargingCurrent +
    571                     ", maxChargingVoltage:" + mBatteryProps.maxChargingVoltage +
    572                     ", chargeCounter:" + mBatteryProps.batteryChargeCounter);
    573         }
    574 
    575         mHandler.post(new Runnable() {
    576             @Override
    577             public void run() {
    578                 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
    579             }
    580         });
    581     }
    582 
    583     private void logBatteryStatsLocked() {
    584         IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
    585         if (batteryInfoService == null) return;
    586 
    587         DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
    588         if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
    589 
    590         File dumpFile = null;
    591         FileOutputStream dumpStream = null;
    592         try {
    593             // dump the service to a file
    594             dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
    595             dumpStream = new FileOutputStream(dumpFile);
    596             batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
    597             FileUtils.sync(dumpStream);
    598 
    599             // add dump file to drop box
    600             db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
    601         } catch (RemoteException e) {
    602             Slog.e(TAG, "failed to dump battery service", e);
    603         } catch (IOException e) {
    604             Slog.e(TAG, "failed to write dumpsys file", e);
    605         } finally {
    606             // make sure we clean up
    607             if (dumpStream != null) {
    608                 try {
    609                     dumpStream.close();
    610                 } catch (IOException e) {
    611                     Slog.e(TAG, "failed to close dumpsys output stream");
    612                 }
    613             }
    614             if (dumpFile != null && !dumpFile.delete()) {
    615                 Slog.e(TAG, "failed to delete temporary dumpsys file: "
    616                         + dumpFile.getAbsolutePath());
    617             }
    618         }
    619     }
    620 
    621     private void logOutlierLocked(long duration) {
    622         ContentResolver cr = mContext.getContentResolver();
    623         String dischargeThresholdString = Settings.Global.getString(cr,
    624                 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
    625         String durationThresholdString = Settings.Global.getString(cr,
    626                 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
    627 
    628         if (dischargeThresholdString != null && durationThresholdString != null) {
    629             try {
    630                 long durationThreshold = Long.parseLong(durationThresholdString);
    631                 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
    632                 if (duration <= durationThreshold &&
    633                         mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {
    634                     // If the discharge cycle is bad enough we want to know about it.
    635                     logBatteryStatsLocked();
    636                 }
    637                 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
    638                         " discharge threshold: " + dischargeThreshold);
    639                 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
    640                         (mDischargeStartLevel - mBatteryProps.batteryLevel));
    641             } catch (NumberFormatException e) {
    642                 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
    643                         durationThresholdString + " or " + dischargeThresholdString);
    644             }
    645         }
    646     }
    647 
    648     private int getIconLocked(int level) {
    649         if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
    650             return com.android.internal.R.drawable.stat_sys_battery_charge;
    651         } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
    652             return com.android.internal.R.drawable.stat_sys_battery;
    653         } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
    654                 || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
    655             if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
    656                     && mBatteryProps.batteryLevel >= 100) {
    657                 return com.android.internal.R.drawable.stat_sys_battery_charge;
    658             } else {
    659                 return com.android.internal.R.drawable.stat_sys_battery;
    660             }
    661         } else {
    662             return com.android.internal.R.drawable.stat_sys_battery_unknown;
    663         }
    664     }
    665 
    666     class Shell extends ShellCommand {
    667         @Override
    668         public int onCommand(String cmd) {
    669             return onShellCommand(this, cmd);
    670         }
    671 
    672         @Override
    673         public void onHelp() {
    674             PrintWriter pw = getOutPrintWriter();
    675             dumpHelp(pw);
    676         }
    677     }
    678 
    679     static void dumpHelp(PrintWriter pw) {
    680         pw.println("Battery service (battery) commands:");
    681         pw.println("  help");
    682         pw.println("    Print this help text.");
    683         pw.println("  set [-f] [ac|usb|wireless|status|level|temp|present|invalid] <value>");
    684         pw.println("    Force a battery property value, freezing battery state.");
    685         pw.println("    -f: force a battery change broadcast be sent, prints new sequence.");
    686         pw.println("  unplug [-f]");
    687         pw.println("    Force battery unplugged, freezing battery state.");
    688         pw.println("    -f: force a battery change broadcast be sent, prints new sequence.");
    689         pw.println("  reset [-f]");
    690         pw.println("    Unfreeze battery state, returning to current hardware values.");
    691         pw.println("    -f: force a battery change broadcast be sent, prints new sequence.");
    692     }
    693 
    694     static final int OPTION_FORCE_UPDATE = 1<<0;
    695 
    696     int parseOptions(Shell shell) {
    697         String opt;
    698         int opts = 0;
    699         while ((opt = shell.getNextOption()) != null) {
    700             if ("-f".equals(opt)) {
    701                 opts |= OPTION_FORCE_UPDATE;
    702             }
    703         }
    704         return opts;
    705     }
    706 
    707     int onShellCommand(Shell shell, String cmd) {
    708         if (cmd == null) {
    709             return shell.handleDefaultCommands(cmd);
    710         }
    711         PrintWriter pw = shell.getOutPrintWriter();
    712         switch (cmd) {
    713             case "unplug": {
    714                 int opts = parseOptions(shell);
    715                 getContext().enforceCallingOrSelfPermission(
    716                         android.Manifest.permission.DEVICE_POWER, null);
    717                 if (!mUpdatesStopped) {
    718                     mLastBatteryProps.set(mBatteryProps);
    719                 }
    720                 mBatteryProps.chargerAcOnline = false;
    721                 mBatteryProps.chargerUsbOnline = false;
    722                 mBatteryProps.chargerWirelessOnline = false;
    723                 long ident = Binder.clearCallingIdentity();
    724                 try {
    725                     mUpdatesStopped = true;
    726                     processValuesFromShellLocked(pw, opts);
    727                 } finally {
    728                     Binder.restoreCallingIdentity(ident);
    729                 }
    730             } break;
    731             case "set": {
    732                 int opts = parseOptions(shell);
    733                 getContext().enforceCallingOrSelfPermission(
    734                         android.Manifest.permission.DEVICE_POWER, null);
    735                 final String key = shell.getNextArg();
    736                 if (key == null) {
    737                     pw.println("No property specified");
    738                     return -1;
    739 
    740                 }
    741                 final String value = shell.getNextArg();
    742                 if (value == null) {
    743                     pw.println("No value specified");
    744                     return -1;
    745 
    746                 }
    747                 try {
    748                     if (!mUpdatesStopped) {
    749                         mLastBatteryProps.set(mBatteryProps);
    750                     }
    751                     boolean update = true;
    752                     switch (key) {
    753                         case "present":
    754                             mBatteryProps.batteryPresent = Integer.parseInt(value) != 0;
    755                             break;
    756                         case "ac":
    757                             mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
    758                             break;
    759                         case "usb":
    760                             mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
    761                             break;
    762                         case "wireless":
    763                             mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
    764                             break;
    765                         case "status":
    766                             mBatteryProps.batteryStatus = Integer.parseInt(value);
    767                             break;
    768                         case "level":
    769                             mBatteryProps.batteryLevel = Integer.parseInt(value);
    770                             break;
    771                         case "temp":
    772                             mBatteryProps.batteryTemperature = Integer.parseInt(value);
    773                             break;
    774                         case "invalid":
    775                             mInvalidCharger = Integer.parseInt(value);
    776                             break;
    777                         default:
    778                             pw.println("Unknown set option: " + key);
    779                             update = false;
    780                             break;
    781                     }
    782                     if (update) {
    783                         long ident = Binder.clearCallingIdentity();
    784                         try {
    785                             mUpdatesStopped = true;
    786                             processValuesFromShellLocked(pw, opts);
    787                         } finally {
    788                             Binder.restoreCallingIdentity(ident);
    789                         }
    790                     }
    791                 } catch (NumberFormatException ex) {
    792                     pw.println("Bad value: " + value);
    793                     return -1;
    794                 }
    795             } break;
    796             case "reset": {
    797                 int opts = parseOptions(shell);
    798                 getContext().enforceCallingOrSelfPermission(
    799                         android.Manifest.permission.DEVICE_POWER, null);
    800                 long ident = Binder.clearCallingIdentity();
    801                 try {
    802                     if (mUpdatesStopped) {
    803                         mUpdatesStopped = false;
    804                         mBatteryProps.set(mLastBatteryProps);
    805                         processValuesFromShellLocked(pw, opts);
    806                     }
    807                 } finally {
    808                     Binder.restoreCallingIdentity(ident);
    809                 }
    810             } break;
    811             default:
    812                 return shell.handleDefaultCommands(cmd);
    813         }
    814         return 0;
    815     }
    816 
    817     private void processValuesFromShellLocked(PrintWriter pw, int opts) {
    818         processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
    819         if ((opts & OPTION_FORCE_UPDATE) != 0) {
    820             pw.println(mSequence);
    821         }
    822     }
    823 
    824     private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
    825         synchronized (mLock) {
    826             if (args == null || args.length == 0 || "-a".equals(args[0])) {
    827                 pw.println("Current Battery Service state:");
    828                 if (mUpdatesStopped) {
    829                     pw.println("  (UPDATES STOPPED -- use 'reset' to restart)");
    830                 }
    831                 pw.println("  AC powered: " + mBatteryProps.chargerAcOnline);
    832                 pw.println("  USB powered: " + mBatteryProps.chargerUsbOnline);
    833                 pw.println("  Wireless powered: " + mBatteryProps.chargerWirelessOnline);
    834                 pw.println("  Max charging current: " + mBatteryProps.maxChargingCurrent);
    835                 pw.println("  Max charging voltage: " + mBatteryProps.maxChargingVoltage);
    836                 pw.println("  Charge counter: " + mBatteryProps.batteryChargeCounter);
    837                 pw.println("  status: " + mBatteryProps.batteryStatus);
    838                 pw.println("  health: " + mBatteryProps.batteryHealth);
    839                 pw.println("  present: " + mBatteryProps.batteryPresent);
    840                 pw.println("  level: " + mBatteryProps.batteryLevel);
    841                 pw.println("  scale: " + BATTERY_SCALE);
    842                 pw.println("  voltage: " + mBatteryProps.batteryVoltage);
    843                 pw.println("  temperature: " + mBatteryProps.batteryTemperature);
    844                 pw.println("  technology: " + mBatteryProps.batteryTechnology);
    845             } else {
    846                 Shell shell = new Shell();
    847                 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
    848             }
    849         }
    850     }
    851 
    852     private void dumpProto(FileDescriptor fd) {
    853         final ProtoOutputStream proto = new ProtoOutputStream(fd);
    854 
    855         synchronized (mLock) {
    856             proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
    857             int batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_NONE;
    858             if (mBatteryProps.chargerAcOnline) {
    859                 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_AC;
    860             } else if (mBatteryProps.chargerUsbOnline) {
    861                 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_USB;
    862             } else if (mBatteryProps.chargerWirelessOnline) {
    863                 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_WIRELESS;
    864             }
    865             proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
    866             proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
    867             proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
    868             proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mBatteryProps.batteryChargeCounter);
    869             proto.write(BatteryServiceDumpProto.STATUS, mBatteryProps.batteryStatus);
    870             proto.write(BatteryServiceDumpProto.HEALTH, mBatteryProps.batteryHealth);
    871             proto.write(BatteryServiceDumpProto.IS_PRESENT, mBatteryProps.batteryPresent);
    872             proto.write(BatteryServiceDumpProto.LEVEL, mBatteryProps.batteryLevel);
    873             proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
    874             proto.write(BatteryServiceDumpProto.VOLTAGE, mBatteryProps.batteryVoltage);
    875             proto.write(BatteryServiceDumpProto.TEMPERATURE, mBatteryProps.batteryTemperature);
    876             proto.write(BatteryServiceDumpProto.TECHNOLOGY, mBatteryProps.batteryTechnology);
    877         }
    878         proto.flush();
    879     }
    880 
    881     private final class Led {
    882         private final Light mBatteryLight;
    883 
    884         private final int mBatteryLowARGB;
    885         private final int mBatteryMediumARGB;
    886         private final int mBatteryFullARGB;
    887         private final int mBatteryLedOn;
    888         private final int mBatteryLedOff;
    889 
    890         public Led(Context context, LightsManager lights) {
    891             mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
    892 
    893             mBatteryLowARGB = context.getResources().getInteger(
    894                     com.android.internal.R.integer.config_notificationsBatteryLowARGB);
    895             mBatteryMediumARGB = context.getResources().getInteger(
    896                     com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
    897             mBatteryFullARGB = context.getResources().getInteger(
    898                     com.android.internal.R.integer.config_notificationsBatteryFullARGB);
    899             mBatteryLedOn = context.getResources().getInteger(
    900                     com.android.internal.R.integer.config_notificationsBatteryLedOn);
    901             mBatteryLedOff = context.getResources().getInteger(
    902                     com.android.internal.R.integer.config_notificationsBatteryLedOff);
    903         }
    904 
    905         /**
    906          * Synchronize on BatteryService.
    907          */
    908         public void updateLightsLocked() {
    909             final int level = mBatteryProps.batteryLevel;
    910             final int status = mBatteryProps.batteryStatus;
    911             if (level < mLowBatteryWarningLevel) {
    912                 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
    913                     // Solid red when battery is charging
    914                     mBatteryLight.setColor(mBatteryLowARGB);
    915                 } else {
    916                     // Flash red when battery is low and not charging
    917                     mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
    918                             mBatteryLedOn, mBatteryLedOff);
    919                 }
    920             } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
    921                     || status == BatteryManager.BATTERY_STATUS_FULL) {
    922                 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
    923                     // Solid green when full or charging and nearly full
    924                     mBatteryLight.setColor(mBatteryFullARGB);
    925                 } else {
    926                     // Solid orange when charging and halfway full
    927                     mBatteryLight.setColor(mBatteryMediumARGB);
    928                 }
    929             } else {
    930                 // No lights if not charging and not low
    931                 mBatteryLight.turnOff();
    932             }
    933         }
    934     }
    935 
    936     private final class BatteryListener extends IBatteryPropertiesListener.Stub {
    937         @Override public void batteryPropertiesChanged(BatteryProperties props) {
    938             final long identity = Binder.clearCallingIdentity();
    939             try {
    940                 BatteryService.this.update(props);
    941             } finally {
    942                 Binder.restoreCallingIdentity(identity);
    943             }
    944        }
    945     }
    946 
    947     private final class BinderService extends Binder {
    948         @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    949             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
    950 
    951             if (args.length > 0 && "--proto".equals(args[0])) {
    952                 dumpProto(fd);
    953             } else {
    954                 dumpInternal(fd, pw, args);
    955             }
    956         }
    957 
    958         @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
    959                 FileDescriptor err, String[] args, ShellCallback callback,
    960                 ResultReceiver resultReceiver) {
    961             (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
    962         }
    963     }
    964 
    965     private final class LocalService extends BatteryManagerInternal {
    966         @Override
    967         public boolean isPowered(int plugTypeSet) {
    968             synchronized (mLock) {
    969                 return isPoweredLocked(plugTypeSet);
    970             }
    971         }
    972 
    973         @Override
    974         public int getPlugType() {
    975             synchronized (mLock) {
    976                 return mPlugType;
    977             }
    978         }
    979 
    980         @Override
    981         public int getBatteryLevel() {
    982             synchronized (mLock) {
    983                 return mBatteryProps.batteryLevel;
    984             }
    985         }
    986 
    987         @Override
    988         public boolean getBatteryLevelLow() {
    989             synchronized (mLock) {
    990                 return mBatteryLevelLow;
    991             }
    992         }
    993 
    994         @Override
    995         public int getInvalidCharger() {
    996             synchronized (mLock) {
    997                 return mInvalidCharger;
    998             }
    999         }
   1000     }
   1001 }
   1002