IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 电池管理(BatteryService) 详解 -> 正文阅读

[移动开发]Android 电池管理(BatteryService) 详解

SystemServer在启动BatteryService时,一次会调用它的构造函数,onStart,onBootPhase方法;解析来我们分析一下这些方法:
1.Constructor方法:
public BatteryService(Context context) {
    super(context);
    mContext = context;
    mHandler = new Handler(true /*async*/);
    //电源呼吸灯
    mLed = new Led(context, getLocalService(LightsManager.class));
    //BatteryStatsService服务,用于统计服务
    mBatteryStats = BatteryStatsService.getService();
    //AMS本地服务
    mActivityManagerInternal = 
            LocalServices.getService(ActivityManagerInternal.class);
    //电量警告值,该值为5
    mCriticalBatteryLevel = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_criticalBatteryWarningLevel);
    //低电量警告值,该值为15
    mLowBatteryWarningLevel = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_lowBatteryWarningLevel);
    //关闭低电量警告的值,为20
    mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + 
            mContext.getResources().getInteger(
            com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
    //高温关机的温度值,该值为68C
    mShutdownBatteryTemperature = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_shutdownBatteryTemperature);
    //设置UEvents监听,监听kernel层上传的无效charge信息
    // watch for invalid charger messages if the invalid_charger switch exists
    if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
        UEventObserver invalidChargerObserver = new UEventObserver() {
            @Override
            public 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");
    }
}
UEvent机制:UEvent机制时kernel通知用户空间的一种机制,很多地方都用到了UEvent机制,入USB插拔/充电等,其本质是内核发送一个字符串(可通过Socket), 应用层接收解释该字符串,获取相应的信息,如果信息有变化,onUEvent方法触发,做出改变;
使用UEvent机制时,需要一个UEventObserver对象,并重写onUEvent(UEvent e)方法,然后调用startObserving方法进行监听,当一个uevent匹配startObserving方法中指定的字符串时触发onUEvent方法;

2.onStart方法:
public void onStart() {
    //获取注册时名为“batteryproperties”的服务
    IBinder b = ServiceManager.getService("batteryproperties");
    final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
            IBatteryPropertiesRegistrar.Stub.asInterface(b);
    try {
        batteryPropertiesRegistrar.registerListener(new BatteryListener());
    } catch (RemoteException e) {
        // Should never happen.
    }
    mBinderService = new BinderService();
    //发布Binder服务
    publishBinderService("battery", mBinderService);
    //发布本地服务
    publishLocalService(BatteryManagerInternal.class, new LocalService());
}
首先获取一个"batteryproperties"的Binder,也即BatteryPropertiesRegistrar,这个服务由healthd层进行注册,底层间隔1分钟,会通过这个服务将电量状态信息更新给BatteryService;
然后,实例化内部类BinderService,该类继承自Binder,然后将这个Binder通过PublishBinderService方法发布到系统服务中;
publishLocalService方法中将BatterySevice的内部类LocalService注册到本地服务;LocalService中提供了一些获取电池相关的方法,且仅限于SystemServer进程内使用;

onBootPhase方法:
public 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) {
                @Override
                public 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();
        }
    }
}
这个方法中设置了ContentObserver观察者,当Settings.Global中低电量触发值改变时,就会触发onChange方法,根据上面分析;

接下来分析updateBatteryWarningLevelLocked方法:
private void updateBatteryWarningLevelLocked() {
    final ContentResolver resolver = mContext.getContentResolver();
    //获取配置文件中存储的低电量触发默认值,15
    int defWarnLevel = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_lowBatteryWarningLevel);
    //获取Settings.Global中存储的低电量触发值
    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);
}

调用更新电池状态信息的核心方法processValuesLocked():
这个是BatteryService最核心的方法,当healthd从kernel层获取电池信息后,会上报给BatteryService,BatteryService中通过这个方法进行处理从而完成更新;
再BatteryService中,有三个地方调用了processValuesLocked方法
1.启动BatteryService时,在onBootPhase方法中的updateBatteryWainingLock方法中;
2.在healthd层向BatteryService更新电池状态信息的update方法中,这里每分钟调用一次;
3.通过adb shell命令dump时在processValuesFromShellLocked方法中;

由于该方法体量较大,我们将分段分析:
1.获取充电类型:
mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
//获取充电类型
if (mBatteryProps.chargerAcOnline) {
    //AC充电
    mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
} else if (mBatteryProps.chargerUsbOnline) {
    //USB充电
    mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
} else if (mBatteryProps.chargerWirelessOnline) {
    //无线充电
    mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
} else {
    //没有充电
    mPlugType = BATTERY_PLUGGED_NONE;
}

2.更新统计电池状态信息:
try {
    //将电池信息交给BatteryStatsService进行统计
    mBatteryStats.setBatteryState(mBatteryProps.batteryStatus,
            mBatteryProps.batteryHealth,
            mPlugType, mBatteryProps.batteryLevel, 
            mBatteryProps.batteryTemperature,
            mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter,
            mBatteryProps.batteryFullCharge);
} catch (RemoteException e) {
    // Should never happen.
}
这里将BatteryProperties中更新的电池信息更新到BatteryStatesService中进行统计;
BatteryProperties是由healthd中传入,实现了Parcelable接口,里面存储了healthd从节点文件中读取的电池信息;

3.进行低电量时和高温时的关机:
//低电量关机
shutdownIfNoPowerLocked();
//高温关机
shutdownIfOverTempLocked();
在电量为0并且没有充电时,会自动关机,当温度高于68时,也会进行自动关机;

4.充电类型改变时获取放电时长和放电量:
if (mPlugType != mLastPlugType) {
    //上次没充电,说明设备由放电进入充电状态
    if (mLastPlugType == BATTERY_PLUGGED_NONE) {
        /**
         * mDischargeStartTime默认为0,在充电进入放电时赋值为当前时间,放电进入
         *充电时又赋值为0
         * mDischargeStartLevel为开始放电时的电量
         * mDischargeStartTime != 0说明有一次充电->放电
         * mDischargeStartLevel!=mBatteryProps.batteryLevel说明电池电量有改变
         */
        if (mDischargeStartTime != 0 && mDischargeStartLevel != 
                       mBatteryProps.batteryLevel) {
            //放电时间段 = 当前时间 - 开始放电时间
            dischargeDuration = SystemClock.elapsedRealtime() - 
                       mDischargeStartTime;
            //重新赋值为0
            mDischargeStartTime = 0;
        }
    } else if (mPlugType == BATTERY_PLUGGED_NONE) {//放电->充电
        // charging -> discharging or we just powered up
        //重新赋值为当前时间
        mDischargeStartTime = SystemClock.elapsedRealtime();
        //重新赋值为当前电量
        mDischargeStartLevel = mBatteryProps.batteryLevel;
    }
}

5.更新低电量临界值:
if (!mBatteryLevelLow) {
    // Should we now switch in to low battery mode?
    //没充电且当前电量小于等于15%
    if (mPlugType == BATTERY_PLUGGED_NONE
            && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
        mBatteryLevelLow = true;
    }
} else {
    //充电时mBatteryLevelLow置为false,退出低电量模式
    if (mPlugType != BATTERY_PLUGGED_NONE) {
        mBatteryLevelLow = false;
        //电量到达20%,退出低电量模式
    } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel)  {
        mBatteryLevelLow = false;
        //force为true时进行强制更新
    } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
        mBatteryLevelLow = false;
    }
}
mBatteryLevelLow是一个用于判断当前电量是否小于低电量警告值得boolean值,和低电量模式有关,在PMS中设置低电量模式时,都会通过LocalService获取到这个值;

6.发送充电/放电模式和到达低电量/退出低电量广播:
/**
 *放电->充电,发送Intent.ACTION_POWER_CONNECTED广播,mSequence每次都会+1,
 *用于记录广播次序,和JobScheduler有关
 *
 *充电->放电,发送Intent.ACTION_POWER_DISCONNECTED广播
 */
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() {
        @Override
        public 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() {
        @Override
        public void run() {
            mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
        }
    });
}
/**
 * 发送电池电量过低广播Intent.ACTION_BATTERY_LOW,该广播在两种情况下发送:
 * 1.设备由充电进入放电(拔掉充电器)后,电量小于15%
 * 2.设备在放电过程中,电量小于15%
 *
 * 当电量达到20%时,发送电池状态正常广播Intent.ACTION_BATTERY_OKAY
 */
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() {
        @Override
        public void run() {
            mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
        }
    });
} else if (mSentLowBatteryBroadcast &&
        mBatteryProps.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() {
        @Override
        public void run() {
            mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
        }
    });
}

7.调用sendIntentLocked方法发送粘性广播:该广播持续性的发送电池电量的变化
private void sendIntentLocked() {
    //  Pack up the values and broadcast them to everyone
    final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
            | Intent.FLAG_RECEIVER_REPLACE_PENDING);
    int icon = getIconLocked(mBatteryProps.batteryLevel);
    intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
    intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
    intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
    intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
    intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
    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, mBatteryProps.batteryVoltage);
    intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, 
                         mBatteryProps.batteryTemperature);
    intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, 
                         mBatteryProps.batteryTechnology);
    intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
    intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, 
                         mBatteryProps.maxChargingCurrent);
    intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, 
                         mBatteryProps.maxChargingVoltage);
    intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, 
                         mBatteryProps.batteryChargeCounter);
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
        }
    });
}

8.更新LED灯状态:
mLed.updateLightsLocked();
public void updateLightsLocked() {
    final int level = mBatteryProps.batteryLevel;
    final int status = mBatteryProps.batteryStatus;
    //电量<15%
    if (level < mLowBatteryWarningLevel) {
        //电池状态处于充电状态
        if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
            // Solid red when battery is charging
            mBatteryLight.setColor(mBatteryLowARGB);
        } else {
            // Flash red when battery is low and not charging
            mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
                    mBatteryLedOn, mBatteryLedOff);
        }
        //电池状态处于充电状态||满电量状态
    } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
            || status == BatteryManager.BATTERY_STATUS_FULL) {
        //处于满电亮状态,或者电量大于90%
        if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
            // Solid green when full or charging and nearly full
            mBatteryLight.setColor(mBatteryFullARGB);
        } else {//电量小于90且充电
            // Solid orange when charging and halfway full
            mBatteryLight.setColor(mBatteryMediumARGB);
        }
    } else {//不处于充电状态
        // No lights if not charging and not low
        mBatteryLight.turnOff();
    }
}

9.更新电池信息:
mLastBatteryStatus = mBatteryProps.batteryStatus;
mLastBatteryHealth = mBatteryProps.batteryHealth;
mLastBatteryPresent = mBatteryProps.batteryPresent;
mLastBatteryLevel = mBatteryProps.batteryLevel;
mLastPlugType = mPlugType;
mLastBatteryVoltage = mBatteryProps.batteryVoltage;
mLastBatteryTemperature = mBatteryProps.batteryTemperature;
mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent;
mLastMaxChargingVoltage = mBatteryProps.maxChargingVoltage;
mLastChargeCounter = mBatteryProps.batteryChargeCounter;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
至此,BatteryService得启动流程和和核心方法就分析完比了,现在剩余内部类BatteryListener了;

BatteryService.BatteryListener:
在分析batteryService得启动过程时,对onStart方法中得IBatteryPropertiesRegistrar和BatteryListener没有深入得分析说明,现在主要研究它们之间的关系和作用;

回到onStart方法中:
public void onStart() {
    //获取名为“batteryproperties”的服务
    IBinder b = ServiceManager.getService("batteryproperties");
    final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
            IBatteryPropertiesRegistrar.Stub.asInterface(b);
    try {
        batteryPropertiesRegistrar.registerListener(new BatteryListener());
    } catch (RemoteException e) {
        // Should never happen.
    }
    ......
}

首先,在系统服务中获取batteryproperties注册的服务,获取到的对象为Binder,那么这个名为batteryProperties的系统服务,它是在何处注册的呢?C++的代码中,找到了batteryProperties注册位置:
\system\core\healthd\BatteryPropertiesRegistrar.cpp
void BatteryPropertiesRegistrar::publish(
    const sp<BatteryPropertiesRegistrar>& service) {
    defaultServiceManager()->addService(String16("batteryproperties"), service);
}

之后对IBatteryPropertiesRegistrar注册一个监听事件,当监听内容改变时回调对应的方法,监听器如下:
private final class BatteryListener extends IBatteryPropertiesListener.Stub {
    @Override public void batteryPropertiesChanged(BatteryProperties props) {
        final long identity = Binder.clearCallingIdentity();
        try {
            BatteryService.this.update(props);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
   }
}

可以看到,BatteryListener继承于IBatteryPropertiesListener.Stub,因此也是一个Binder对象,当监听内容发生变化时,回调方法batteryPropertiesChanged方法中调用update方法:
private void update(BatteryProperties props) {
    synchronized (mLock) {
        if (!mUpdatesStopped) {
            mBatteryProps = props;
            // Process the new values.
            processValuesLocked(false);
        } else {
            mLastBatteryProps.set(props);
        }
    }
}
在这个方法中,通过监听器传入到BatteryProperties初始化成员变量mBatteryProps;BatteryProperties中带有电池状态信息,通过该方法最终调用processValuesLocked方法,从而完成电池状态信息的更新;

电池服务架构图

参考文档:
电池服务管理-详解

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:47:44  更:2022-04-22 18:50:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 22:26:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码