1.充电图标不显示,问题分析步骤
a)找到充电图标的UI,frameworks/base/packages/SystemUI/res/layout/system_icons.xml
中找到1
2
3
4<com.android.systemui.BatteryMeterView android:id="@+id/battery"
android:layout_height="match_parent"
android:layout_width="wrap_content"
/>
确定充电图标UI文件,BatteryMeterView.java
frameworks/base/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
中充电图标绘制在BatteryMeterDrawableBase.java,查看
frameworks/base/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java可以看到充电的闪电图标的绘制过程。
在BatteryMeterView.java中可以看到充电图标的显示与否是由下面决定的:1
2
3
4
5
6
7
8
9
10@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
mDrawable.setBatteryLevel(level);
mDrawable.setCharging(pluggedIn);//pluggedIn为true,显示闪电图标,为false则不显示
mLevel = level;
updatePercentText();
setContentDescription(
getContext().getString(charging ? R.string.accessibility_battery_level_charging
: R.string.accessibility_battery_level, level));
}
可以看到是由pluggedIn来决定是否显示,这里有个疑问,为何不用charging的值来判断,而要用pluggedIn的值来判断。原因在下面这个代码,
onBatteryLevelChanged这个函数,是在
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java里面addCallback回调过去的。
mCharging的值是由 mCharged和 BATTERY_STATUS_CHARGING两个值一起判断的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Override
public void onReceive(final Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
mHasReceivedBattery = true;
mLevel = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
mCharged = status == BatteryManager.BATTERY_STATUS_FULL;
mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING;
fireBatteryLevelChanged();
}
为了查看手机中当前的pluggedIn和charging这两个值的状态,从
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java文件中看到了一个Dump 的log打印,刚好打印了这几个值的状态,如下:1
2
3
4
5
6
7
8
9@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("BatteryController state:");
pw.print(" mLevel="); pw.println(mLevel);
pw.print(" mPluggedIn="); pw.println(mPluggedIn);
pw.print(" mCharging="); pw.println(mCharging);
pw.print(" mCharged="); pw.println(mCharged);
pw.print(" mPowerSave="); pw.println(mPowerSave);
}
所以,不需要另外打任何的log,直接连接手机,使用adb shell bugreport > bugreport.txt
抓出所有的dump log即可。
BatteryController state:
mLevel=86
mPluggedIn=false
mCharging=true
mCharged=false
mPowerSave=false
01-01 10:23:19.490 1000 1098 1110 D BatteryService: Sending ACTION_BATTERY_CHANGED. level:71, scale:100, status:3, health:2, present:true, voltage: 3962, temperature: 375, technology: Li-ion, AC powered:false, USB powered:false, Wireless powered:false, icon:17303429, invalid charger:0, maxChargingCurrent:0, maxChargingVoltage:0, chargeCounter:1714883
-------------------------------------------------------------------------------
DUMP OF SERVICE batteryproperties:
ac: 0 usb: 0 wireless: 0 current_max: 0 voltage_max: 0
status: 2 health: 2 present: 1
level: 86 voltage: 4234 temp: 297
current now: -77209
charge counter: 2089873
current now: -376
Full charge: 2444000
--------- 0.003s was the duration of dumpsys batteryproperties, ending at: 2018-06-15 16:17:57
这里有个问题,adb shell bugreport的log在User版本和Userdebug的版本里面抓出来的结果不一样,具体原因,可能是日志的级别限制的,需要查证一下。
2.mPluggedIn的值是在收到ACTION_BATTERY_CHANGED广播里面带的参数得到的,那么这个广播是哪里发出来的呢?
通过使用http://androidxref.com 进行全局搜索,找到是在
/frameworks/base/services/core/java/com/android/server/BatteryService.java的sendIntentLocked()函数里面发出来的。代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34private 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);
EXTRA_PLUGGED的值是由mPlugType得到的,而mPlugType的值在BatteryService.java中得到方式如下:
private void processValuesLocked(boolean force) {
boolean logOutlier = false;
long dischargeDuration = 0;
mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
if (mBatteryProps.chargerAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
} else if (mBatteryProps.chargerUsbOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
} else if (mBatteryProps.chargerWirelessOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
} else {
mPlugType = BATTERY_PLUGGED_NONE;
}
从中可以看出是根据mBatteryProps.chargerAcOnline或者mBatteryProps.chargerUsbOnline或者mBatteryProps.chargerWirelessOnline的值来判断,在
frameworks/base/core/java/android/os/BatteryProperties.java中,可以看到这三个值是通过序列化的方式得到:
1 | private BatteryProperties(Parcel p) { |
再来看看mBatteryProps的赋值:
1 | private void update(BatteryProperties props) { |
接着看update()函数的调用,如下:
1 | private final class BatteryListener extends IBatteryPropertiesListener.Stub { |
可以看到BatteryProperties是在由batteryPropertiesChanged赋值,是通过AIDL实现对C++侧的监听,这个AIDL实现了JAVA侧与C++侧的通讯。
这一块关于电池的共有三个AIDL文件,作为客户端和服务端的媒介,具体代码,以及作用分析如下:
1 | frameworks/base/core/java/android/os/BatteryProperties.aidl |
BatteryProperties.aidl主要用户AIDL跨进程通讯时的数据序列化和反序列化frameworks/base/core/java/android/os/BatteryProperties.java
1 | frameworks/base/core/java/android/os/IBatteryPropertiesListener.aidl |
IBatteryPropertiesListener.aidl主要用于监听
1 | frameworks/base/core/java/android/os/IBatteryPropertiesRegistrar.aidl |
IBatteryPropertiesRegistrar.aidl主要用于注册
服务端在BatteryService.java
1 | @Override |
对应的native层的代码在frameworks/native/services/batteryservice/编译出libbatteryservice.so库
Java侧与C++侧通过AIDL通讯,两边都要写AIDL文件,且两边都要有Parcel序列化。
通过查找batteryPropertiesChanged函数
system/core/healthd/BatteryPropertiesRegistrar.cpp
1 | #include "BatteryPropertiesRegistrar.h" |
再查找notifyListeners函数,在 system/core/healthd/healthd_mode_android.cpp
1 | void healthd_mode_android_battery_update( |
Healthd是一种中介模型,向下监听来自kernel层的电池事件,向上将电池数据信息传递给Framework层的BatteryService.
主要代码在 system/core/healthd 中,对Healthd模块的代码分析如下:
参考:
Healthd模块编译出来的文件有system/bin/healthd
通过在system/core/healthd里面查找chargerUsbOnline,在system/core/healthd/BatteryMonitor.cpp中update函数可以看到赋值:
1 | bool BatteryMonitor::update(void) { |
从上面代码可以看到chargerUsbOnline的值是通过读取 sys/class/power_supply文件夹下的USB文件夹下的type里面的值来判断。
adb shell进入手机后,cd sys/class/power_supply/USB,cat type发现是USB。
这下懵逼了,这个值是对的呀,为何log里面读取出来的值不对呢?而且从之前抓的dump log来看如下:的确没有正确的读取到
-------------------------------------------------------------------------------
DUMP OF SERVICE batteryproperties:
ac: 0 usb: 0 wireless: 0 current_max: 0 voltage_max: 0
status: 2 health: 2 present: 1
level: 86 voltage: 4234 temp: 297
current now: -77209
charge counter: 2089873
current now: -376
Full charge: 2444000
--------- 0.003s was the duration of dumpsys batteryproperties, ending at: 2018-06-15 16:17:57
现在怀疑是SeAndroid的AVC权限导致的。