[Android Framework] 8.1 Battery系列(一) BatteryService分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/FightFightFight/article/details/82353373

概述

BatteryService负责监听充电状态和电量变化,当电量值或者充电类型改变时,会获取到底层healthd上报的电池状态信息,并更新到BatteryStatsService中进行统计,同时会将这些值存储到Intent中,以广播的形式发送到监听了ACTION_BATTERY_CHANGED的组件中,其他组建可以通过Intent.getExtra()的方式获取到电池信息。

1.BatteryService的启动流程

BatteryService继承于SyetemService,SyetemService是所有系统服务的基类,每个SyetemService的启动流程都具有相同的步骤,他们实现并重写其父类方法。因此,在分析BatteryService之前,先看看SystemServer的启动相关方法。SystemServer启动时调用方法如下,并且都是在SystemServer的main线程中运行:

  • 1.Constructor():构造方法,通过反射的方式调用;
  • 2.onStart():开始运行服务;
  • 3.onBootPhase(int):该方法表示启动阶段,会根据不同的参数(阶段)调用多次,直到PHASE_BOOT_COMPLETED阶段调用后不再调用,表示启动完成,对于每个阶段,可以完成特定的工作;

了解了上述内容后,着手分析BatteryService就容易多了,首先,BatteryService会在SystemServer中进行启动:

/**
 * The main entry point from zygote.
 */
public static void main(String[] args) {
    new SystemServer().run();
}

启动SystemServer后,在main()函数中调用了run()方法,在run()方法中,启动三种服务:

private void run() {
    ......
// Start services.
    try {
    //启动引导服务
        startBootstrapServices();
    //启动核心服务
        startCoreServices();
    //启动其他服务
        startOtherServices();
    //关闭启动线程池
        SystemServerInitThreadPool.shutdown();
    ......
    } catch (Throwable ex) {
        throw ex;
    } finally {
        traceEnd();
    }
}

startBootstrapServices()中启动的是一些依赖性比较高的系统服务(所以方法名为”引导服务”),如PMS就是在这里进行启动的。
startCoreServices()中启动一些核心服务,从代码中看,启动的核心服务有四种,其中就包括要分析的BatteryService。
startOtherServices()用来启动其他的一些服务。

startCoreServices()中,通过SystemServiceManager中的方法,传入类名作为参数,利用反射机制对BatteryService进行实例化:

public <T extends SystemService> T startService(Class<T> serviceClass) {
    try {
        final String name = serviceClass.getName();
        ......
        final T service;
        try {
            Constructor<T> constructor = serviceClass.getConstructor(Context.class);
            service = constructor.newInstance(mContext);
        } catch (InstantiationException ex) 
        }
        startService(service);
        return service;
    } finally {
    }
}
public void startService(@NonNull final SystemService service) {
    // Register it.
    mServices.add(service);
    long time = SystemClock.elapsedRealtime();
    try {
        //调用onStart()方法开启服务
        service.onStart();
    } catch (RuntimeException ex) {
    }
}

分析到这一步,SystemServive的生命周期方法就剩下onBootPhase()方法了,这个方法也说过了,是负责启动启动服务的过程中分阶段进行一些工作的,也运行在SystemServer的main线程中:

private void startOtherServices() {
    ......
    mSystemServiceManager.startBootPhase(
          SystemService.PHASE_LOCK_SETTINGS_READY);
    mSystemServiceManager.startBootPhase(
          SystemService.PHASE_SYSTEM_SERVICES_READY);
    mSystemServiceManager.startBootPhase(
              SystemService.PHASE_ACTIVITY_MANAGER_READY);
    mSystemServiceManager.startBootPhase(
              SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
    mSystemServiceManager.startBootPhase(
              SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
    ......
 }

SystemServiceManager中:

public void startBootPhase(final int phase) {
    ......
    mCurrentPhase = phase;
    try {
        final int serviceLen = mServices.size();
        for (int i = 0; i < serviceLen; i++) {
            final SystemService service = mServices.get(i);
            long time = SystemClock.elapsedRealtime();
            try {
                service.onBootPhase(mCurrentPhase);
            } catch (Exception ex) {
            }
        }
    } finally {
    }
}

到这里,SystemServer中启动BatteryService相关的内容就完毕了,现在依次看看在SystemServer中启动时,BatteryService中的构造方法、onStart()方法、onBootPhase()方法中都做了些什么。

1.1.Constructor()

首先看调用构造方法时的处理,在BatteryService中:

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");
    }
}

在构造方法中,详细信息都进行了注释,这里有两点需重点说明一下,先看第一点:初始化了mBatteryStats,该对象类型为IBatteryStats,这里使用了Binder机制,在分析BatteryStatsService时将会知道,BatteryStatsService继承于IBatteryStats.Stub,因此,可以把BatteryStatsService作为Binder的服务端来使用,接着来看一下BatteryStatsService的getService()方法:

public static IBatteryStats getService() {
    if (sService != null) {
        return sService;
    }
    IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME);
    sService = asInterface(b);
    return sService;
}

通过ServiceManager.getService(String)获取了一个IBinder对象,并将IBinder对象转换为客户端需要的类型返回;如此一来,BatteryService中就获取到了IBatteryStats接口,从而可以和BatteryStatsService进行交互。

再分析第二点:UEvent机制。UEvent是kernel通知用户空间的一种机制,很多地方都用到了UEvent机制,如USB插拔/充电等,其本质是内核发送一个字符串(可通过Socket),应用层接受并解释该字符串,获取相应信息,如果信息有变化,onUEevent()触发,做出改变。
使用该机制时,需要一个UEventObserver对象,并重写onUEvent(UEvent e)方法,然后调用startObserving()进行监听,当一个uevent匹配startObserving(String)中指定的string时触发onUEvent();

1.2.onStart()

到这时,BatteryService的构造方法分析完毕了,根据启动流程,接下来执行的是第二步,onStart()方法,如下:

@Override
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());
}

onStart()中,首先获取了一个“batterypropeties”的Binder,也即IBatteryPropertiesRegistrar,这个服务由healthd层进行注册,底层每间隔1分钟,会通过这个服务将电池状态信息更新给BatteryService.
然后,实例化了内部类BinderService,该类继承自Binder,然后将这个Binder通过publishBinderService()发布到了系统服务中,就像之前分析PowerManagerService一样,目的是可以通过getSystemService(String)来获取其实例。
publishLocalService()方法中将BatteryService的内部类LocalService注册到了本地服务中,LocalService中提供了一些getxxx()获取电池相关的方法,且仅限于SystemServer进程内使用。

1.3.onBootPhase()

onStart()方法调用之后,开始调用onBootPhase()方法:

@Override
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();
        }
    }
}

在这个方法中,设置了一个ContentObverser观察者,当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);
}

这个方法中更新了低电量警告值和关闭低电量警告的值,在资源文件中定义的值如下:

<!-- Display low battery warning when battery level dips to this value -->
<integer name="config_lowBatteryWarningLevel">15</integer>
<!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel plus this -->
<integer name="config_lowBatteryCloseWarningBump">5</integer>

从以上内容可知,默认情况下,当电量达到15%时会弹出低电量提示。

在上述方法的最后,调用了processValuesLocked()方法,它是BatteryService中最核心的方法,因此这里从启动流程中分离出来,单独进行分析。

2.processValuesLocked()

processValuesLocked()是BatteryService中更新电池信息最核心的方法,当healthd从kernel层获取电池信息后,会上报给BatteryService,BatteryService中通过这个方法进行处理从而完成更新。

在BatteryService中,有三个地方调用了processValuesLocked():

  • 1.启动BatteryService时,在onBootPhase()方法中的updateBatteryWarningLock()方法中;
  • 2.在healthd层向BatteryService更新电池状态信息的update()方法中,这里会每分钟调用一次;
  • 3.通过adb shell命令dump时在processValuesFromShellLocked()中。

由于该方法体较大,因此分段来进行分析:

2.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.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中最新的电池信息更新到了BatteryStatsService中进行统计;BatteryProperties是由healthd中传入,实现了Parcelable接口,里面存储了healthd中从节点文件中读取的电池信息。

2.3.进行低电量时和高温时的关机

//低电量关机
shutdownIfNoPowerLocked();
//高温关机
shutdownIfOverTempLocked();

当电量为0并且没有充电时,会自动关机;当电池温度高于68C时,也会进行自动关机;

2.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;
    }
}

2.5.更新低电量临界值

//mBatteryLevelLow表示当前电量是否小于等于低电量警告值
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是一个用于判断当前电量是否小于低电量警告值的bool值,和低电量模式有关,在PMS中设置低电量模式时,都会通过LocalService获取到这个值。

2.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);
        }
    });
}

2.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);
        }
    });
}

在该方法中,发送了Action为Intent.ACTION_BATTERY_CHANGED的粘性广播,并将所有电池信息存储到Intent中,当BroadcastReceiver接收到后,就可以从中获取到电池信息(至于这里为何在其它普通广播之后发送BATTERY_CHANGED的粘性广播,还有待于研究)。

2.8.更新LED灯状态

mLed.updateLightsLocked();

看看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();
        }
    }
}

2.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了。

3.BatteryService.BatteryListener

在分析BatteryService的启动过程时,对onstart()方法中的IBatteryPropertiesRegistrarBatteryListener没有深入的分析说明,现在主要研究他们之间的关系和作用。

回到onStart()方法中:

@Override
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”的系统服务,它是在何处进行注册的呢?
我在Java代码中搜索后,没有发现对应的注册代码,难不成它没有进行注册?这是不可能的。经过全局搜索发现了其注册位置,在c++代码中,路径为:\system\core\healthd\BatteryPropertiesRegistrar.cpp.

void BatteryPropertiesRegistrar::publish(
    const sp<BatteryPropertiesRegistrar>& service) {
    defaultServiceManager()->addService(String16("batteryproperties"), service);
}

这里涉计到了Healthd相关东西,在之后的文章中进行分析。
之后对IBatteryPropertiesRegistrar 注册一个监听事件,当监听内容改变时回调对应方法,监听器如下:


//healthd中每间隔1分钟上报一次,该方法也会进行回调
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);
        }
   }
}

可以看到,BaytteryListener继承于IBatteryPropertiesListener.Stub,因此也是一个Binder对象;当监听内容发生变化时,回调方法batteryPropertiesChanged()中调用update(BatteryProperties)方法:

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(false)方法,从而完成电池状态信息的更新。

4.电池信息状态及其属性值

充电类型:

字段 含义
BATTERY_PLUGGED_NONE 0 没有充电
BATTERY_PLUGGED_AC 1 AC充电
BATTERY_PLUGGED_USB 2 USB充电
BATTERY_PLUGGED_WIRELESS 4 无线充电
BATTERY_PLUGGED_ANY 7 除BATTERY_PLUGGED_NONE外以上

充电状态:

字段 含义
BATTERY_STATUS_UNKNOWN 1 未知
BATTERY_STATUS_CHARGING 2 正在充电
BATTERY_STATUS_DISCHARGING 3 放电中
BATTERY_STATUS_NOT_CHARGING 4 没有充电
BATTERY_STATUS_FULL 5 电充满了

健康状态:

字段 含义
BATTERY_HEALTH_UNKNOWN 1 未知
BATTERY_HEALTH_GOOD 2 良好
BATTERY_HEALTH_OVERHEAT 3 过热
BATTERY_HEALTH_DEAD 4 没电
BATTERY_HEALTH_OVER_VOLTAGE 5 电压过高
BATTERY_HEALTH_UNSPECIFIED_FAILURE 6 未知
BATTERY_HEALTH_COLD 7 过冷

猜你喜欢

转载自blog.csdn.net/FightFightFight/article/details/82353373