【Android 10 源码】healthd 模块 BatteryService 初始化

2024-05-01 20:58

本文主要是介绍【Android 10 源码】healthd 模块 BatteryService 初始化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 初始化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/952652

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存