电池电量分析

本文将从底层到上层介绍android系统中电量显示这一块,电池检测采用的是ADC采样,不是使用市场上封装好的电量计芯片;

1.驱动层

    linux内核中提供power_supply_core.c电池管理核心,我们驱动程序主要完成核心给我们提供的接口:battery.get_property,在这个程序中,我们主要获得电池的电压、是否正常、容量、充放电状态等;通过这些值来改变文件系统中/sys/class/power_supply/目录下的文件值,下面主要介绍以上几个参数的获取方法:

    1)电池充放电状态gBatChargeStatus:

        当DC插入时,会产生一个中断,在这个中断处理程序中,我们主要完成给全局变量gBatChargeStatus赋值,如果DC插入,则gBatChargeStatus=1,否则为0,同事,在中断处理程序中,调用send_wakeup_key()唤醒触摸屏;

    2)电池状态

        电池状态主要有:充电、放电、电量满三种状态;当DC没插入时,电池处于放电状态,当DC插入时,如果电池电池芯片没有报电量满切电量达到100%则为充电状态,否则为充电状态

    3)电压值

        电压值采用ADC模块对电池电压的采样,获得电池的电压值,因为系统在使用过程中可能存在跳变,所以,对电池电压的获得最好采取多次采样取平均值的方法。在通过adc读电压值的时候,可以采取同步读或者异步读,区别是异步读在第二次执行这个程序的时候获取第一次执行的结果,这样做的好处就是效率高点;

    4)电量值

        电量值是用户实际看的的值,是用户最关心的,也是最重要的值,在处理电量值的时候注意,充电状态下电量值不能降低,放电状态下电量值不能升高,而且电量值不能大弧度跨越,基本是按照1%这样的变化;特别要注意的是在低电量和电量接近100%的时候的处理。

        电量值主要是根据测得的电压值获取,在开始写驱动前,得获得两组数据,分别是充电和没充电下没10%对应的电压值,切两组数据需要对应上,不如在电量为50%的时候,如果没接DC测得的电压值可能为3700而接着DC测得的电压值可能为3800,所以每一个百分比最好都能对应上。

    获取这些值后,驱动里每隔50ms就会调用一次比较函数,确认以上的几个值是否改变,如果改变了,则调用power_supply_changed()->kobject->uevent()上报uevent事件。同事电池管理核心就会调用接口battery.get_property更新/sys/class/power_supply目录下的值拱上层调用。

2.获取电池状态值

BatteryService作为电池及充电相关的服务,它的实现非常简单:监听UEvent,读取sysfs里中的状态。实现了一个UEvent的观察者,uevent是Linux内核用来向用户空间主动上报事件的机制,对于JAVA程序来说,只实现UEventObserver的虚函数onUEvent,然后注册即可。

private UEventObserver mUEventObserver = new UEventObserver() {
         @Override
         public void onUEvent(UEventObserver.UEvent event) {
         String strOnline = event.get("POWER_SUPPLY_ONLINE");   //电源连接状态
         String strBatteryState = event.get("POWER_SUPPLY_STATUS");

         //电池状态,"Discharging","Charging","Not charging","Full","Unknown"
         String strBatteryLevel = event.get("POWER_SUPPLY_CAPACITY");//电池容量
            ...
         }
   }

 1).BatteryService通过JNI(com_android_server_BatteryService.cpp)读取数据。BatteryService通过JNI注册的不仅有函数,还有变量。 如下:
   //##############在BatteryService.java中声明的变量################
   private boolean mAcOnline;
     private boolean mUsbOnline;
   private int mBatteryStatus;
   private int mBatteryHealth;
   private boolean mBatteryPresent;
   private int mBatteryLevel;
   private int mBatteryVoltage;
   private int mBatteryTemperature;
   private String mBatteryTechnology;

 2).在BatteryService.java中声明的变量,在com_android_server_BatteryService.cpp 中共用,即在com_android_server_BatteryService.cpp中其实操作的也是BatteryService.java中声明的变量
   gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
   gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
   gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
   gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
   gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
   gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
   gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;");
   gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I");
     gFieldIds.mBatteryTemperature= env->GetFieldID(clazz, "mBatteryTemperature", "I");

 3).上面这些变量的值,对应是从下面的文件中读取的,一个文件存储一个数值。
    #define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"   AC电源连接状态 

    #define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"USB电源连接状
  #define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"充电状
   #define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"电池状
   #define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"状态
    #define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"   电池容量
    #define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"    电池电压
   #define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"   电池温度
   #define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology"   电池技术

update然后根据读到的状态更新BatteryService的成员变量,并广播一个Intent来通知其它关注电源状态的组件。

private final void sendIntent() {
        //  Pack up the values and broadcast them to everyone
        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        try {
            mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE, mBatteryLevel);
        } catch (RemoteException e) {
            // Should never happen.
        }
        int icon = getIcon(mBatteryLevel);
        intent.putExtra("status", mBatteryStatus);
        intent.putExtra("health", mBatteryHealth);
        intent.putExtra("present", mBatteryPresent);
        intent.putExtra("level", mBatteryLevel);

...........
        ActivityManagerNative.broadcastStickyIntent(intent, null);
    }

3.根据电池状态值改变UI

关注ACTION_BATTERY_CHANGED的地方有好几个:
1) KeyguardUpdateMonitor 这里主要是用来更新锁屏界面下的电池状态和低电关机

    private void handleBatteryUpdate(int pluggedInStatus, int batteryLevel) {
        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
        final boolean pluggedIn = isPluggedIn(pluggedInStatus);

        if (isBatteryUpdateInteresting(pluggedIn, batteryLevel)) {
            mBatteryLevel = batteryLevel;
            mDevicePluggedIn = pluggedIn;
            for (int i = 0; i < mInfoCallbacks.size(); i++) {
                mInfoCallbacks.get(i).onRefreshBatteryInfo(
                        shouldShowBatteryInfo(), pluggedIn, batteryLevel);
            }
        }
        // shut down gracefully if our battery is critically low and we are not powered
        if (batteryLevel == 0 &&
                pluggedInStatus != BATTERY_STATUS_CHARGING &&
                pluggedInStatus != BATTERY_STATUS_UNKNOWN) {
            ShutdownThread.shutdownAfterDisablingRadio(mContext, false);
        }
    }

2 )NotificationManagerService 用来更新充电状态(LED)
      if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
          boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0);
          int level = intent.getIntExtra("level", -1);
          boolean batteryLow = (level >= 0 && level <=    Power.LOW_BATTERY_THRESHOLD);
          int status = intent.getIntExtra("status",    BatteryManager.BATTERY_STATUS_UNKNOWN);
          boolean batteryFull = (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90);
          if (batteryCharging != mBatteryCharging ||
                    batteryLow != mBatteryLow ||
                    batteryFull != mBatteryFull) {
                    mBatteryCharging = batteryCharging;
                    mBatteryLow = batteryLow;
                    mBatteryFull = batteryFull;
                    updateLights();
                }
            }

3 )PowerManagerService 这里主要是做两件事件,先是检查是否在充电时不允许睡眠,并采用相应的行动,其次是触发一个用户行为(会影响下一次睡眠的时间)。

    private final class BatteryReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            synchronized (mLocks) {
                boolean wasPowered = mIsPowered;
                mIsPowered = mBatteryService.isPowered();
                if (mIsPowered != wasPowered) {
                    updateWakeLockLocked();.
                    synchronized (mLocks) {
                        boolean savedActivityAllowed = mUserActivityAllowed;
                        mUserActivityAllowed = true;
                        userActivity(SystemClock.uptimeMillis(), false);
                        mUserActivityAllowed = savedActivityAllowed;
                    }
                }
            }
        }
    }

4 )LocationManagerService 这里似乎没有什么用处,我没找到mCollector赋值的地方。
             if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                log("PowerStateBroadcastReceiver: Battery changed");
                synchronized (mLocationListeners) {
                    int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100);
                    int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0);
                    boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0;
                    if (mCollector != null) {
                        mCollector.updateBatteryState(scale, level, plugged);
                    }
                }
            }

5 )WifiService 根据电源状态来决定是否需要定时唤醒
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
            int pluggedType = intent.getIntExtra("plugged", 0);
        if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) && !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
            long triggerTime = System.currentTimeMillis() + idleMillis;
            mAlARMManager.set(AlARMManager.RTC_WAKEUP, triggerTime, mIdleIntent);
            mPluggedType = pluggedType;
            return;
            }
            mPluggedType = pluggedType;
            }

6 )StatusBarPolicy用来更新状态栏上的充电图标。
    if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
              updateBattery(intent);
            }
7)发送低电警报
首先需要判断是否需要发送低电量信息:Intent.ACTION_BATTERY_LOW

       final boolean sendBatteryLow = !plugged && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN

       && mBatteryLevel <= mLowBatteryWarningLevel

       && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);

可以看到发送低电量信息会有两个条件,

1)当前不在充电状态,上次update时处于充电状态,并且电池电量小于等于mLowBatteryWarningLevel(低电量警告值)

2)当前不在充电状态,电池电量小于等于mLowBatteryWarningLevel(低电量警告值),并且上次update时,电量大于mLowBatteryWarningLevel(低电量警告值)

下面代码是具体发送

   if (sendBatteryLow) {

       mSentLowBatteryBroadcast = true;

       statusIntent.setAction(Intent.ACTION_BATTERY_LOW);

       mContext.sendBroadcast(statusIntent);

       }else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {

       mSentLowBatteryBroadcast = false;

       statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);

       mContext.sendBroadcast(statusIntent);

       }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MTK电池电量同步是指在使用MTK芯片的设备上,系统会实时地更新显示电池的剩余电量情况。然而,有时候我们可能会遇到电量同步不准确的情况。 导致MTK电池电量同步问题的原因可能有多种。首先,电池老化可能是一个导致不准确电量显示的原因。随着时间的推移,电池容量会逐渐减小,从而导致电量显示不准确。此外,使用的充电器和数据线的质量也会影响电量同步。如果使用的充电器和数据线质量不好,可能会导致电量显示不准确或者无法正确充电。 其次,操作系统的错误或软件问题也可能导致电量同步不准确。如果设备的操作系统或者某些应用程序存在缺陷,可能会导致电量显示不准确。这时,我们可以尝试更新系统或者卸载一些有问题的应用程序,以解决电量同步问题。 此外,使用电池优化应用程序也可能会影响电池电量同步。有些电池优化应用程序可能会对电池电量进行优化管理,但有时候可能会造成电量同步不准确的情况。因此,我们可以尝试调整或关闭电池优化应用程序,查看是否能够解决电量同步问题。 总结来说,MTK电池电量同步问题可能由电池老化、充电器、数据线质量、操作系统错误、软件问题和电池优化应用程序等多个因素造成。通过检查和调整这些因素,我们可以尝试解决电量同步不准确的问题,以保证设备正常使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值