How BatteryService works in android.

本文介绍了Android系统中BatteryService如何监测设备电池的状态变化,并通过BroadcastReceiver广播更新后的信息。文章详细解释了如何读取系统文件来获取电池的充电状态、健康状况等信息,并触发系统在特定条件下自动关机的安全措施。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BatteryService monitors the charging status, and charge level of the device battery. When these values change this service broadcasts the new values to all IntentReceivers (android.content.BroadcastReceiver) that are watching the BATTERY_CHANGED (android.content.Intent#ACTION_BATTERY_CHANGED) action.

The new values are stored in the Intent data and can be retrieved by calling Intent.getExtra (android.content.Intent#getExtra) with the following keys:
 "scale" - int, the maximum value for the charge level.
 "level" - int, charge level, from 0 through "scale" inclusive.
 "status" - String, the current charging status.
 "health" - String, the current battery health.
 "present" - boolean, true if the battery is present.
 "icon-small" - int, suggested small icon to use for this state.
 "plugged" - int, 0 if the device is not plugged in; 1 if plugged into an AC power adapter; 2 if plugged in via USB.
 "voltage" - int, current battery voltage in millivolts.
 "temperature" - int, current battery temperature in tenths of a degree Centigrade.
 "technology" - String, the type of battery installed, e.g. "Li-ion".

1. mUEventObserver.startObserving("SUBSYSTEM=power_supply");
    private UEventObserver mUEventObserver = new UEventObserver() {
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
            update();
        }
    };

Observe power supply status. When there is a change, it update the battery status by invoking the update method.
 
2. update
The battery information is required by invoking the native_update method, which is implemented in the file frameworks/base/services/jni/com_android_server_battery_service.cpp.
In fact, all these information is required from the system file /sys/class/power_supply.
(For more infomation, we need to dig inside Linux kernel.)

static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
{
    setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
    setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);
    setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
   
    setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
    setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage);
    setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature);
   
    const int SIZE = 128;
    char buf[SIZE];
   
    if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0)
        env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
    else
        env->SetIntField(obj, gFieldIds.mBatteryStatus,
                         gConstants.statusUnknown);
   
    if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0)
        env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));

    if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
        env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
}

static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
    {"native_update", "()V", (void*)android_server_BatteryService_update},
};
--------------------------------------------------
Also, we could see that two method will be invoked. From the name you will know what they are doing.
        shutdownIfNoPower();
        shutdownIfOverTemp();
   
    private final void shutdownIfOverTemp() {
        // shut down gracefully if temperature is too high (> 68.0C)
        // wait until the system has booted before attempting to display the shutdown dialog.
        if (mBatteryTemperature > 680 && ActivityManagerNative.isSystemReady()) {
            Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
            intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(intent);
        }
    }

Finally, if either status changes, it will notify the observers.

Android开发中,`getApplicationContext()` 是 `ContextWrapper` 类的一个方法,用于获取应用的全局上下文。当你在单元测试中尝试对 `ContextWrapper` 或其子类进行Mockito模拟时,可能会遇到无法mock `getApplicationContext()` 的问题,因为这个方法直接关联到真实的应用环境。 解决这个问题通常有以下几种方法: 1. 使用Mockito提供的`@Mock`注解和`when()`方法创建mock对象: ```java @Mock private Context context; // 在测试方法里设置mock的行为 when(context.getApplicationContext()).thenReturn(mockedAppContext); ``` 这里你需要先创建一个`mockedAppContext` 对象作为返回值。 2. 使用@RunWith(MockitoJUnitRunner.class) 运行测试: 如果你的测试已经在运行上下文中,可以考虑使用`MockitoJUnitRunner`替代`Junit4`的`runTest()`方法,它会自动处理静态依赖注入,如`ApplicationContext`。 ```java @RunWith(MockitoJUnitRunner.class) public class YourTestClass { @InjectMocks private YourClassToTest yourClass; // ...其他测试方法... } ``` 然后在`YourClassToTest`类上添加`@InjectMocks`注解,让Mockito管理类的所有字段初始化。 3. 使用PowerMock库: 如果`getApplicationContext()`是从`Application`类中获取的,而`Application`是单例且不可Mock,你可以使用PowerMock库的`@PrepareForTest`和`@Test`注解,动态替换`ApplicationContext`。 ```java import static org.powermock.api.mockito.PowerMockito.mockStatic; @Test @PrepareForTest(Application.class) public void testMethod() { mockStatic(Application.class); Application application = PowerMockito.mock(Application.class); when(application.getApplicationContext()).thenReturn(yourMockedContext); // 测试代码 // ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值