BatteryService 是在 SystemServer 中启动的,BatteryService 监控设备电池的充电状态和充电水平。当这些值改变时,这个服务会将这些新值广播给所有正在监听 ACTION_BATTERY_CHANGED 的广播接收者。

BatteryService 被划分到核心服务类别。

frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer {......private void startCoreServices() {traceBeginAndSlog("StartBatteryService");// Tracks the battery level.  Requires LightService.mSystemServiceManager.startService(BatteryService.class);traceEnd();......}......
}

SystemServiceManager startService(Class serviceClass) 通过反射的方式构造了 BatteryService。构造完后就会调用其重载版本的函数 startService(@NonNull final SystemService service) 正在启动它。

frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

public class SystemServiceManager {......@SuppressWarnings("unchecked")public <T extends SystemService> T startService(Class<T> serviceClass) {try {final String name = serviceClass.getName();Slog.i(TAG, "Starting " + name);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);// Create the service.if (!SystemService.class.isAssignableFrom(serviceClass)) {throw new RuntimeException("Failed to create " + name+ ": service must extend " + SystemService.class.getName());}final T service;try {Constructor<T> constructor = serviceClass.getConstructor(Context.class);service = constructor.newInstance(mContext);} catch (InstantiationException ex) {throw new RuntimeException("Failed to create service " + name+ ": service could not be instantiated", ex);} catch (IllegalAccessException ex) {throw new RuntimeException("Failed to create service " + name+ ": service must have a public constructor with a Context argument", ex);} catch (NoSuchMethodException ex) {throw new RuntimeException("Failed to create service " + name+ ": service must have a public constructor with a Context argument", ex);} catch (InvocationTargetException ex) {throw new RuntimeException("Failed to create service " + name+ ": service constructor threw an exception", ex);}startService(service);return service;} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}}public void startService(@NonNull final SystemService service) {// Register it.mServices.add(service);// Start it.long time = SystemClock.elapsedRealtime();try {service.onStart();} catch (RuntimeException ex) {throw new RuntimeException("Failed to start service " + service.getClass().getName()+ ": onStart threw an exception", ex);}warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");}......
}


从上图中的 BatteryService 作用不难看出其承上启下,向上给 BatteryManager 提供支撑,向下则通过静态内部类 HealthServiceWrapper 连接 HAL。

BatteryService 构造函数中获取到了 BatteryStatsService 代理,电池 Led 控制类,AMS 内部接口类 ActivityManagerInternal。以及一些关键电量配置参数:

mCriticalBatteryLevel —— 电池危急电量(当电池电量下降到这个值时,显示低电量警告,在设备关闭之前,用于确定何时做最后的努力来记录放电状态)

mLowBatteryWarningLevel —— 电池低电量警告电量

mLowBatteryCloseWarningLevel —— 关闭低电量警告电量

mShutdownBatteryTemperature —— 电池过热触发关机温度

另外,还注册了一个监听无效充电器的消息订阅者。前提是 /sys/devices/virtual/switch/invalid_charger/state 路径存在。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......public BatteryService(Context context) {super(context);mContext = context;mHandler = new Handler(true /*async*/);mLed = new Led(context, getLocalService(LightsManager.class));mBatteryStats = BatteryStatsService.getService();mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);mCriticalBatteryLevel = mContext.getResources().getInteger(com.android.internal.R.integer.config_criticalBatteryWarningLevel);mLowBatteryWarningLevel = mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryCloseWarningBump);mShutdownBatteryTemperature = mContext.getResources().getInteger(com.android.internal.R.integer.config_shutdownBatteryTemperature);mBatteryLevelsEventQueue = new ArrayDeque<>();mMetricsLogger = new MetricsLogger();// watch for invalid charger messages if the invalid_charger switch existsif (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {UEventObserver invalidChargerObserver = new UEventObserver() {@Overridepublic void onUEvent(UEvent event) {final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;synchronized (mLock) {if (mInvalidCharger != invalidCharger) {mInvalidCharger = invalidCharger;}}}};invalidChargerObserver.startObserving("DEVPATH=/devices/virtual/switch/invalid_charger");}}    ......
}

走到这里就会调到 BatteryService onStart() 方法。

  1. 调用 registerHealthCallback() 注册 Health 回调;
  2. 调用 publishBinderService(…) 发布 battery、batteryproperties 服务;
  3. 调用 publishLocalService(…) 发布本地服务 BatteryManagerInternal(电池管理器本地系统服务接口)。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......@Overridepublic void onStart() {registerHealthCallback();mBinderService = new BinderService();publishBinderService("battery", mBinderService);mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);publishLocalService(BatteryManagerInternal.class, new LocalService());}......
}
  1. new 了一个 HealthServiceWrapper 对象,看得出来它是 Health Service 的一层封装,它和 HAL 层建立起了联系;
  2. new 了一个 HealthHalCallback 对象,不难从名字看出它是 Health HAL 回调用到的;
  3. 开始查找 IHealth,通过调用 HealthServiceWrapper init(…) 函数实现;
  4. 等待 mHealthInfo 初始化,没有初始化之前一直触发 while 循环,只不过每次在锁上最长休息 HEALTH_HAL_WAIT_MS (1000 ms)。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private void registerHealthCallback() {traceBegin("HealthInitWrapper");mHealthServiceWrapper = new HealthServiceWrapper();mHealthHalCallback = new HealthHalCallback();// IHealth is lazily retrieved.try {mHealthServiceWrapper.init(mHealthHalCallback,new HealthServiceWrapper.IServiceManagerSupplier() {},new HealthServiceWrapper.IHealthSupplier() {});} catch (RemoteException ex) {Slog.e(TAG, "health: cannot register callback. (RemoteException)");throw ex.rethrowFromSystemServer();} catch (NoSuchElementException ex) {Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");throw ex;} finally {traceEnd();}traceBegin("HealthInitWaitUpdate");// init register for new service notifications, and IServiceManager should return the// existing service in a near future. Wait for this.update() to instantiate// the initial mHealthInfo.long beforeWait = SystemClock.uptimeMillis();synchronized (mLock) {while (mHealthInfo == null) {Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) +"ms for callbacks. Waiting another " + HEALTH_HAL_WAIT_MS + " ms...");try {mLock.wait(HEALTH_HAL_WAIT_MS);} catch (InterruptedException ex) {Slog.i(TAG, "health: InterruptedException when waiting for update. "+ " Continuing...");}}}Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)+ "ms and received the update.");traceEnd();}......
}

HealthServiceWrapper 包装了内部的 IHealth 服务,并在必要时刷新服务。init 应该在构造函数之后调用。HealthServiceWrapper 构造函数内部什么也没做!

不过值得注意的是,sAllInstances 是个 List 结构(按照优先级 高-> 低 排序 ),内部包含了两个字符串分别是 backup 和 default,这是用来检索 IHealth 服务的。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......@VisibleForTestingstatic final class HealthServiceWrapper {private static final String TAG = "HealthServiceWrapper";public static final String INSTANCE_HEALTHD = "backup";public static final String INSTANCE_VENDOR = "default";// All interesting instances, sorted by priority high -> low.private static final List<String> sAllInstances =Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);private final IServiceNotification mNotification = new Notification();private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceRefresh");// These variables are fixed after init.private Callback mCallback;private IHealthSupplier mHealthSupplier;private String mInstanceName;// Last IHealth service received.private final AtomicReference<IHealth> mLastService = new AtomicReference<>();HealthServiceWrapper() {}        ......}......
}

再来分析 HealthHalCallback 类,继承自 IHealthInfoCallback.Stub,并实现 HealthServiceWrapper.Callback 接口。

当底层 Health Service (实现 IHealth 接口)调用 healthInfoChanged(…) 远程返回(入参中返回) android.hardware.health.V2_0.HealthInfo 时,调用 BatteryService update(…) 更新各种信息(mHealthInfo 结构也被更新了)。

新的 Service(实现 IHealth 接口)注册则调用 onRegistration(…) 进一步处理:

  1. 取消 old Service 内回调对象(指向 HealthHalCallback 具体对象);
  2. 添加本对象到 new Service 内;
  3. 调用 new Service update(),服务用最近的运行状况信息通知所有已注册的回调,这会触发 healthInfoChanged(…) 回调。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private final class HealthHalCallback extends IHealthInfoCallback.Stubimplements HealthServiceWrapper.Callback {@Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {BatteryService.this.update(props);}// on new service registered@Override public void onRegistration(IHealth oldService, IHealth newService,String instance) {if (newService == null) return;traceBegin("HealthUnregisterCallback");try {if (oldService != null) {int r = oldService.unregisterCallback(this);if (r != Result.SUCCESS) {Slog.w(TAG, "health: cannot unregister previous callback: " +Result.toString(r));}}} catch (RemoteException ex) {Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "+ ex.getMessage());} finally {traceEnd();}traceBegin("HealthRegisterCallback");try {int r = newService.registerCallback(this);if (r != Result.SUCCESS) {Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));return;}// registerCallback does NOT guarantee that update is called// immediately, so request a manual update here.newService.update();} catch (RemoteException ex) {Slog.e(TAG, "health: cannot register callback (transaction error): "+ ex.getMessage());} finally {traceEnd();}}}......
}

回到 HealthServiceWrapper init(…) 函数。先来重点关注其入参 IServiceManagerSupplier 和 IHealthSupplier。这两个接口,都有一个默认 get() 方法实现,分别返回了 android.hidl.manager.V1_0.IServiceManager 和
android.hardware.health.V2_0.IHealth。

  1. 遍历 sAllInstances List,获取实现 IHealth 接口的代理,先查询名称为 default 的服务,如果不存在则查询名为 backup 的服务;
  2. 调用 Callback 的 onRegistration(…) 方法,这实际会调到 HealthHalCallback 具体实现中的 onRegistration(…) 方法;
  3. 启动 HandlerThread,这个 HandlerThread 只在 Notification onRegistration(…) 回调方法中进行了使用;
  4. 调用 registerForNotifications(…) 为特定服务注册服务通知。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......@VisibleForTestingstatic final class HealthServiceWrapper {......void init(Callback callback,IServiceManagerSupplier managerSupplier,IHealthSupplier healthSupplier)throws RemoteException, NoSuchElementException, NullPointerException {if (callback == null || managerSupplier == null || healthSupplier == null)throw new NullPointerException();IServiceManager manager;mCallback = callback;mHealthSupplier = healthSupplier;// Initialize mLastService and call callback for the first time (in init thread)IHealth newService = null;for (String name : sAllInstances) {traceBegin("HealthInitGetService_" + name);try {newService = healthSupplier.get(name);} catch (NoSuchElementException ex) {/* ignored, handled below */} finally {traceEnd();}if (newService != null) {mInstanceName = name;mLastService.set(newService);break;}}if (mInstanceName == null || newService == null) {throw new NoSuchElementException(String.format("No IHealth service instance among %s is available. Perhaps no permission?",sAllInstances.toString()));}mCallback.onRegistration(null, newService, mInstanceName);// Register for future service registrationstraceBegin("HealthInitRegisterNotification");mHandlerThread.start();try {managerSupplier.get().registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);} finally {traceEnd();}Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);}....../*** Supplier of services.* Must not return null; throw {@link NoSuchElementException} if a service is not available.*/interface IServiceManagerSupplier {default IServiceManager get() throws NoSuchElementException, RemoteException {return IServiceManager.getService();}}/*** Supplier of services.* Must not return null; throw {@link NoSuchElementException} if a service is not available.*/interface IHealthSupplier {default IHealth get(String name) throws NoSuchElementException, RemoteException {return IHealth.getService(name, true /* retry */);}}......}    ......
}

调用 registerForNotifications(…) 为特定服务注册服务通知,如果底层的服务注册有变动就会触发出注册通知回调,对于支持 IHealth.kInterfaceName 中提供的版本的所有服务,必须发送 onRegistration。如此 HealthServiceWrapper 就能感知底层服务的变动。

如果匹配的服务已经注册,onRegistration(…) 必须发送 preexisting = true。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......@VisibleForTestingstatic final class HealthServiceWrapper {......private class Notification extends IServiceNotification.Stub {@Overridepublic final void onRegistration(String interfaceName, String instanceName,boolean preexisting) {if (!IHealth.kInterfaceName.equals(interfaceName)) return;if (!mInstanceName.equals(instanceName)) return;// This runnable only runs on mHandlerThread and ordering is ensured, hence// no locking is needed inside the runnable.mHandlerThread.getThreadHandler().post(new Runnable() {@Overridepublic void run() {try {IHealth newService = mHealthSupplier.get(mInstanceName);IHealth oldService = mLastService.getAndSet(newService);// preexisting may be inaccurate (race). Check for equality here.if (Objects.equals(newService, oldService)) return;Slog.i(TAG, "health: new instance registered " + mInstanceName);mCallback.onRegistration(oldService, newService, mInstanceName);} catch (NoSuchElementException | RemoteException ex) {Slog.e(TAG, "health: Cannot get instance '" + mInstanceName+ "': " + ex.getMessage() + ". Perhaps no permission?");}}});}}}......
}

现在开始分析调用 publishBinderService(…) 发布 battery、batteryproperties 服务。BinderService 只是重写了 Binder dump 和 onShellCommand 方法。重点关注下 batteryproperties 服务。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private final class BinderService extends Binder {@Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;if (args.length > 0 && "--proto".equals(args[0])) {dumpProto(fd);} else {dumpInternal(fd, pw, args);}}@Override public void onShellCommand(FileDescriptor in, FileDescriptor out,FileDescriptor err, String[] args, ShellCallback callback,ResultReceiver resultReceiver) {(new Shell()).exec(this, in, out, err, args, callback, resultReceiver);}}    ......
}

BatteryPropertiesRegistrar 只实现 getProperty 在 BatteryManager 中使用。

getProperty(…) 实现非常简单,主要依赖 IHealth 代理接口,获取各种电池信息,比如电流、容量等。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub {@Overridepublic int getProperty(int id, final BatteryProperty prop) throws RemoteException {traceBegin("HealthGetProperty");try {IHealth service = mHealthServiceWrapper.getLastService();if (service == null) throw new RemoteException("no health service");final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);switch(id) {case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:service.getChargeCounter((int result, int value) -> {outResult.value = result;if (result == Result.SUCCESS) prop.setLong(value);});break;case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:service.getCurrentNow((int result, int value) -> {outResult.value = result;if (result == Result.SUCCESS) prop.setLong(value);});break;case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:service.getCurrentAverage((int result, int value) -> {outResult.value = result;if (result == Result.SUCCESS) prop.setLong(value);});break;case BatteryManager.BATTERY_PROPERTY_CAPACITY:service.getCapacity((int result, int value) -> {outResult.value = result;if (result == Result.SUCCESS) prop.setLong(value);});break;case BatteryManager.BATTERY_PROPERTY_STATUS:service.getChargeStatus((int result, int value) -> {outResult.value = result;if (result == Result.SUCCESS) prop.setLong(value);});break;case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:service.getEnergyCounter((int result, long value) -> {outResult.value = result;if (result == Result.SUCCESS) prop.setLong(value);});break;}return outResult.value;} finally {traceEnd();}}@Overridepublic void scheduleUpdate() throws RemoteException {traceBegin("HealthScheduleUpdate");try {IHealth service = mHealthServiceWrapper.getLastService();if (service == null) throw new RemoteException("no health service");service.update();} finally {traceEnd();}}}......
}

调用 publishLocalService(…) 发布本地服务 BatteryManagerInternal(电池管理器本地系统服务接口)。LocalService 实现了抽象类 BatteryManagerInternal 定义的接口方法,主要通过返回 mHealthInfo 指向的 HealthInfo 中的字段提供支撑。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private final class LocalService extends BatteryManagerInternal {@Overridepublic boolean isPowered(int plugTypeSet) {synchronized (mLock) {return isPoweredLocked(plugTypeSet);}}@Overridepublic int getPlugType() {synchronized (mLock) {return mPlugType;}}@Overridepublic int getBatteryLevel() {synchronized (mLock) {return mHealthInfo.batteryLevel;}}@Overridepublic int getBatteryChargeCounter() {synchronized (mLock) {return mHealthInfo.batteryChargeCounter;}}@Overridepublic int getBatteryFullCharge() {synchronized (mLock) {return mHealthInfo.batteryFullCharge;}}@Overridepublic boolean getBatteryLevelLow() {synchronized (mLock) {return mBatteryLevelLow;}}@Overridepublic int getInvalidCharger() {synchronized (mLock) {return mInvalidCharger;}}}    ......
}

到此, onStart() 方法才执行完毕了,下一个阶段当调用 SystemServer 中 startOtherServices() 后,会执行到 SystemServiceManager startBootPhase(…),入参为 SystemService.PHASE_ACTIVITY_MANAGER_READY,表征 AMS 已就位。此时就会遍历 SystemServiceManager 记录的 ArrayList 中的每个 SystemService 对象,并执行其 onBootPhase(…) 方法,这就包括 BatteryService 的 onBootPhase(…) 方法。

  1. new 一个 ContentObserver,其回调 onChange(…) 方法内调用 updateBatteryWarningLevelLocked() 进一步处理;
  2. 调用 registerContentObserver(…) 注册上一步创建的 ContentObserver,并马上调用 updateBatteryWarningLevelLocked()。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......@Overridepublic void onBootPhase(int phase) {if (phase == PHASE_ACTIVITY_MANAGER_READY) {// check our power situation now that it is safe to display the shutdown dialog.synchronized (mLock) {ContentObserver obs = new ContentObserver(mHandler) {@Overridepublic void onChange(boolean selfChange) {synchronized (mLock) {updateBatteryWarningLevelLocked();}}};final ContentResolver resolver = mContext.getContentResolver();resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),false, obs, UserHandle.USER_ALL);updateBatteryWarningLevelLocked();}}}......
}

updateBatteryWarningLevelLocked() 主要干的工作就是更新 mLowBatteryWarningLevel 的值,结合上面的代码片段不难知道,当 LOW_POWER_MODE_TRIGGER_LEVEL 的值变更时,就会被监听到,从而更新 BatteryService 中的 mLowBatteryWarningLevel 字段,以及其关联的动作。

此处最后会调用 processValuesLocked(…) 进一步处理,这在更新电池信息时我们再来重点分析。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private void updateBatteryWarningLevelLocked() {final ContentResolver resolver = mContext.getContentResolver();int defWarnLevel = mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);mLowBatteryWarningLevel = Settings.Global.getInt(resolver,Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);if (mLowBatteryWarningLevel == 0) {mLowBatteryWarningLevel = defWarnLevel;}if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {mLowBatteryWarningLevel = mCriticalBatteryLevel;}mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryCloseWarningBump);processValuesLocked(true);}......
}

前面谈到当底层 Health Service (实现 IHealth 接口)调用 healthInfoChanged(…) 远程返回(入参中返回) android.hardware.health.V2_0.HealthInfo 时,调用 BatteryService update(…) 更新各种信息(mHealthInfo 结构也被更新了)。

  1. HealthInfo.legacy 字段赋值给 mHealthInfo,从名字不难看出是为了兼容而为之;
  2. 调用 processValuesLocked(…) 处理新的值。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private void update(android.hardware.health.V2_0.HealthInfo info) {traceBegin("HealthInfoUpdate");Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter",info.legacy.batteryChargeCounter);Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent",info.legacy.batteryCurrent);synchronized (mLock) {if (!mUpdatesStopped) {mHealthInfo = info.legacy;// Process the new values.processValuesLocked(false);mLock.notifyAll(); // for any waiters on new info} else {copy(mLastHealthInfo, info.legacy);}}traceEnd();}......
}

processValuesLocked(…) 函数有点长。

  1. 更新 mBatteryLevelCritical 的值,判断是否进入危机电量状态;
  2. 更新供电类型 mPlugType(AC、USB、无线或者未知);
  3. 更新远程 BatteryStats;
  4. 调用 shutdownIfNoPowerLocked() 判断是否触发低电量关机,当 HealthInfo.batteryLevel 等于 0,并且未充电时触发;
  5. 调用 shutdownIfOverTempLocked() 电池温度过高时自动关机;
  6. force 入参控制是否强制更新,否则只有在信息变动时才去更新;

(1) 判断充电状态变化,并记录日志;
(2) 记录 BATTERY_STATUS、BATTERY_LEVEL 日志;
(3) 记录未充电状态下放电时长 dischargeDuration;
(4) 判断是否进入低电量模式(mBatteryLevelLow);
(5) mSequence 序列号 +1;
(6) 发送电源连接、未连接、低电量、电池 OK 广播,只在系统启动阶段发送给已注册的广播接收者,供系统使用;
(7) 调用 sendBatteryChangedIntentLocked() 发送电池电量变化广播;
(8) 更新电池 LED 颜色、状态等;
(9) 将 HealthInfo 字段的值赋给对应的 mLastXXX 字段,为下一次是否更新电池信息做准备。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private void processValuesLocked(boolean force) {boolean logOutlier = false;long dischargeDuration = 0;mBatteryLevelCritical =mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN&& mHealthInfo.batteryLevel <= mCriticalBatteryLevel;if (mHealthInfo.chargerAcOnline) {mPlugType = BatteryManager.BATTERY_PLUGGED_AC;} else if (mHealthInfo.chargerUsbOnline) {mPlugType = BatteryManager.BATTERY_PLUGGED_USB;} else if (mHealthInfo.chargerWirelessOnline) {mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;} else {mPlugType = BATTERY_PLUGGED_NONE;}if (DEBUG) {Slog.d(TAG, "Processing new values: "+ "info=" + mHealthInfo+ ", mBatteryLevelCritical=" + mBatteryLevelCritical+ ", mPlugType=" + mPlugType);}// Let the battery stats keep track of the current level.try {mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,mHealthInfo.batteryFullCharge);} catch (RemoteException e) {// Should never happen.}shutdownIfNoPowerLocked();shutdownIfOverTempLocked();if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||mHealthInfo.batteryHealth != mLastBatteryHealth ||mHealthInfo.batteryPresent != mLastBatteryPresent ||mHealthInfo.batteryLevel != mLastBatteryLevel ||mPlugType != mLastPlugType ||mHealthInfo.batteryVoltage != mLastBatteryVoltage ||mHealthInfo.batteryTemperature != mLastBatteryTemperature ||mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||mHealthInfo.batteryChargeCounter != mLastChargeCounter ||mInvalidCharger != mLastInvalidCharger)) {if (mPlugType != mLastPlugType) {if (mLastPlugType == BATTERY_PLUGGED_NONE) {// discharging -> chargingmChargeStartLevel = mHealthInfo.batteryLevel;mChargeStartTime = SystemClock.elapsedRealtime();final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);builder.setType(MetricsEvent.TYPE_ACTION);builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mPlugType);builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,mHealthInfo.batteryLevel);mMetricsLogger.write(builder);// 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 != mHealthInfo.batteryLevel) {dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;logOutlier = true;EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,mDischargeStartLevel, mHealthInfo.batteryLevel);// make sure we see a discharge event before logging againmDischargeStartTime = 0;}} else if (mPlugType == BATTERY_PLUGGED_NONE) {// charging -> discharging or we just powered upmDischargeStartTime = SystemClock.elapsedRealtime();mDischargeStartLevel = mHealthInfo.batteryLevel;long chargeDuration = SystemClock.elapsedRealtime() - mChargeStartTime;if (mChargeStartTime != 0 && chargeDuration != 0) {final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);builder.setType(MetricsEvent.TYPE_DISMISS);builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastPlugType);builder.addTaggedData(MetricsEvent.FIELD_CHARGING_DURATION_MILLIS,chargeDuration);builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,mChargeStartLevel);builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_END,mHealthInfo.batteryLevel);mMetricsLogger.write(builder);}mChargeStartTime = 0;}}if (mHealthInfo.batteryStatus != mLastBatteryStatus ||mHealthInfo.batteryHealth != mLastBatteryHealth ||mHealthInfo.batteryPresent != mLastBatteryPresent ||mPlugType != mLastPlugType) {EventLog.writeEvent(EventLogTags.BATTERY_STATUS,mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0,mPlugType, mHealthInfo.batteryTechnology);}if (mHealthInfo.batteryLevel != mLastBatteryLevel) {// Don't do this just from voltage or temperature changes, that is// too noisy.EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature);}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;}if (!mBatteryLevelLow) {// Should we now switch in to low battery mode?if (mPlugType == BATTERY_PLUGGED_NONE&& mHealthInfo.batteryStatus !=BatteryManager.BATTERY_STATUS_UNKNOWN&& mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) {mBatteryLevelLow = true;}} else {// Should we now switch out of low battery mode?if (mPlugType != BATTERY_PLUGGED_NONE) {mBatteryLevelLow = false;} else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel)  {mBatteryLevelLow = false;} else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) {// If being forced, the previous state doesn't matter, we will just// absolutely check to see if we are now above the warning level.mBatteryLevelLow = false;}}mSequence++;// Separate broadcast is sent for power connected / not connected// since the standard intent will not wake any applications and some// applications may want to have smart behavior based on this.if (mPlugType != 0 && mLastPlugType == 0) {final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});}else if (mPlugType == 0 && mLastPlugType != 0) {final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});}if (shouldSendBatteryLowLocked()) {mSentLowBatteryBroadcast = true;final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});} else if (mSentLowBatteryBroadcast &&mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {mSentLowBatteryBroadcast = false;final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});}// We are doing this after sending the above broadcasts, so anything processing// them will get the new sequence number at that point.  (See for example how testing// of JobScheduler's BatteryController works.)sendBatteryChangedIntentLocked();if (mLastBatteryLevel != mHealthInfo.batteryLevel || mLastPlugType != mPlugType) {sendBatteryLevelChangedIntentLocked();}// Update the battery LEDmLed.updateLightsLocked();// This needs to be done after sendIntent() so that we get the lastest battery stats.if (logOutlier && dischargeDuration != 0) {logOutlierLocked(dischargeDuration);}mLastBatteryStatus = mHealthInfo.batteryStatus;mLastBatteryHealth = mHealthInfo.batteryHealth;mLastBatteryPresent = mHealthInfo.batteryPresent;mLastBatteryLevel = mHealthInfo.batteryLevel;mLastPlugType = mPlugType;mLastBatteryVoltage = mHealthInfo.batteryVoltage;mLastBatteryTemperature = mHealthInfo.batteryTemperature;mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;mLastChargeCounter = mHealthInfo.batteryChargeCounter;mLastBatteryLevelCritical = mBatteryLevelCritical;mLastInvalidCharger = mInvalidCharger;}}......
}

最后看一眼 sendBatteryChangedIntentLocked() 实现,看到最后调用 broadcastStickyIntent(…) 发出了粘性广播,这包括了电池电量、健康状态、电池电压等 APP 需要监听的信息。

frameworks/base/services/core/java/com/android/server/BatteryService.java

public final class BatteryService extends SystemService {......private void sendBatteryChangedIntentLocked() {//  Pack up the values and broadcast them to everyonefinal Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY| Intent.FLAG_RECEIVER_REPLACE_PENDING);int icon = getIconLocked(mHealthInfo.batteryLevel);intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);intent.putExtra(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology);intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);if (DEBUG) {Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE+ ", info:" + mHealthInfo.toString());}mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL));}......
}

【Android 10 源码】healthd 模块 BatteryService 初始化相关推荐

  1. 【Android 10 源码】healthd 模块 HAL 2.0 分析

    Android 9 引入了从 health@1.0 HAL 升级的主要版本 android.hardware.health HAL 2.0.这一新 HAL 具有以下优势: 框架代码和供应商代码之间的区 ...

  2. 【Android 10 源码】深入理解 Omx 初始化

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  3. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 初始化

    MediaRecorder 用于录制音频和视频,录制控制基于一个简单的状态机.下面是典型的使用 camera2 API 录制,需要使用到的 MediaRecorder API. MediaRecord ...

  4. Ubuntu18.04 编译Android 10源码 并烧录源码到pixel3的避坑指南

    Ubuntu18.04 编译Android 10源码 并烧录源码到pixel3的避坑指南 实验环境 下载Android源码树 在pixel3上安装手机驱动版本 编译Android源码 Android ...

  5. 【Android 10 源码】深入理解 software Codec2 服务启动

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  6. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 配置

    MediaRecorder 录像配置主要涉及输出文件路径.音频来源.视频来源.输出格式.音频编码格式.视频编码格式.比特率.帧率和视频尺寸等. 我们假设视频输入源来自 Camera,Camera2 A ...

  7. 【Android 10 源码】深入理解 MediaCodec 组件分配

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  8. nginx源码分析—模块及其初始化

    Content 0. 序 1. nginx有哪些模块? 2. nginx如何描述这些模块? 2.1 模块数据结构 2.1.1 ngx_module_t结构 2.1.2 ngx_command_t结构 ...

  9. 【Android 10 源码】healthd 模块 HAL 1.0 分析

    health@1.0:android.hardware.health@1.0 的缩写.指的是 Android 8.0 中发布的运行状况 HIDL 的 1.0 版 HAL. Android 8.x 中的 ...

最新文章

  1. linux kernel list_head
  2. SD-WAN的四大错误观念
  3. python画图-用Python画图
  4. 【设计模式】策略模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
  5. linux 脚本$字符,一文看懂shell脚本中$0 $1 $# $@ $* $? $$ 的各种符号意义
  6. 测试色谱柱柱效的软件,高效液相色谱柱柱效测定
  7. 350 个在家办公的人,创造了估值 10 亿美元的代码共享平台
  8. 在资本寒冬下,程序员为何也能迅速找到好工作
  9. JAVA线程池 之 Executors (一) 简介
  10. 可以识别linux的GHOST,Linux可以用ghost
  11. 新手建站之【网站备案】③
  12. 多重共线性分析 与 方差膨胀因子VIF
  13. 《Delta-Sigma数据转换器从入门到精通》笔记之漫谈均值
  14. Java程序,判断一个字母是元音还是辅音
  15. Django企业开发实战--by胡阳,学习记录1015
  16. CF1129C Morse Code
  17. 可达性分析算法中根节点有哪些
  18. c++ 按分割符(忽略多次出现)切割string字符串
  19. 苏州计算机活动,CCF苏州成功举办走进姑苏实验室活动
  20. 控诉理科男(蒋方舟)

热门文章

  1. I-P-B frame简介
  2. Cisco ASA 5585 with firepower upgrade 升级 配置证书
  3. GridView横向显示 实现图片预览
  4. 青玉案.元夕-2023
  5. python自学-class14(down)-窗口界面的设计基础
  6. revit综合建模步骤:怎么设置整个楼层显示在一个视图上
  7. 虚拟化——ovirt删除host主机操作步骤
  8. 模型优化与tensorflow
  9. 解决Sqoop导出数据报错Can‘t parse input data 和 NoSuchElementException
  10. 基于Java+SSM+MySQL的高校就业创业信息管理系统