MTK 关机充电时充电IC正常,电池正常充电,但是充电动画一直显示0%
平台
mt8168+mt6357+chargerIC
问题
MTK 关机充电时充电IC正常,电池正常充电,但是充电动画一直显示0%
相关说明
只截取部分记录一下思路 on charger 触发 工程中的一些on charger配置用于开机时(bootmode is charger)充电触发。 如:device\mediatek\mt8168\init.mt8168.rc
on charger
wait /sys/bus/platform/devices/mt6357-charger-type-detection 10
symlink /dev/block/platform/soc/11230000.mmc /dev/block/platform/bootdevice
chown system system /sys/power/autosleep
chown system system /sys/power/state
chown system system /sys/power/wakeup_count
chown radio wakelock /sys/power/wake_lock
chown radio wakelock /sys/power/wake_unlock
chmod 0660 /sys/power/state
chmod 0660 /sys/power/wake_lock
chmod 0660 /sys/power/wake_unlock
chmod 0660 /sys/power/wakeup_count
start kpoc_charger
chmod 0666 /dev/kmsg
chmod 0775 /mnt/vendor
mkdir /mnt/vendor/nvcfg
mount ext4 /dev/block/platform/bootdevice/by-name/nvcfg /mnt/vendor/nvcfg rw wait
chown system system /mnt/vendor/nvcfg
chmod 0771 /mnt/vendor/nvcfg
restorecon_recursive /mnt/vendor/nvcfg
write /sys/devices/platform/battery_meter/FG_daemon_log_level 7
write /sys/bus/platform/devices/battery/FG_daemon_log_level 7
start fuelgauged
start fuelgauged_nvram
chown system system /sys/class/leds/lcd-backlight/brightness
chown system system /sys/class/leds/red/brightness
chown system system /sys/class/leds/green/brightness
write /sys/devices/platform/mt_usb/cmode 0
hardware\interfaces\health\2.1\default\android.hardware.health@2.1-service.rc
service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
class hal charger
user system
group system
capabilities WAKE_ALARM BLOCK_SUSPEND
file /dev/kmsg w
vendor\mediatek\proprietary\external\charger 关机充电时调用的服务。 kpoc_charger.rc内容:
on charger
start kpoc_charger
service kpoc_charger /system/bin/kpoc_charger
class charger
group system wakelock
capabilities BLOCK_SUSPEND SYS_ADMIN SYS_BOOT
启动流程(\system\core\init\init.cpp)中判断是否充电模式开机判断如下:
int SecondStageMain(int argc, char** argv) {
。。。
std::string bootmode = GetProperty("ro.bootmode", "");
LOG(INFO) << "init : xmhxj debug : bootmode is " << bootmode;
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
。。。
}
hardware\interfaces\health 提供vendor和system的接口调用。 如电量获取getCapacity: hardware\interfaces\health\2.0\default\Health.cpp
Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
return Void();
}
关联调用的是: system\core\healthd\BatteryMonitor.cpp
status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
status_t ret = BAD_VALUE;
std::string buf;
val->valueInt64 = LONG_MIN;
switch(id) {
。。。
case BATTERY_PROP_CAPACITY:
if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCapacityPath);
ret = OK;
} else {
ret = NAME_NOT_FOUND;
}
break;
。。。
return ret;
}
healthd服务相关(system\core\healthd ),用于关机充电时获取电池信息的地方。 void BatteryMonitor::updateValues函数,更新底层上报的电池信息
void BatteryMonitor::updateValues(void) {
initHealthInfo(mHealthInfo.get());
HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :mHealthdConfig->batteryPresentPath.isEmpty() %d\n", mHealthdConfig->batteryPresentPath.isEmpty());
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :mHealthdConfig->batteryPresentPath %s\n",mHealthdConfig->batteryPresentPath.string());
if (!mHealthdConfig->batteryPresentPath.isEmpty()){
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :!mHealthdConfig->batteryPresentPath.isEmpty() %s\n", mHealthdConfig->batteryPresentPath.string());
props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
} else {
props.batteryPresent = mBatteryDevicePresent;
KLOG_WARNING(LOG_TAG, "BM xmhxj debug : mHealthdConfig->batteryPresentPath.isEmpty() mBatteryDevicePresent %d\n", mBatteryDevicePresent);
}
KLOG_WARNING(LOG_TAG, "BM xmhxj debug : props.batteryPresent %d\n", props.batteryPresent);
props.batteryLevel = mBatteryFixedCapacity ?
mBatteryFixedCapacity :
getIntField(mHealthdConfig->batteryCapacityPath);
props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath);
if (!mHealthdConfig->batteryFullChargePath.isEmpty())
props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
mHealthInfo->legacy.batteryCurrentAverage =
getIntField(mHealthdConfig->batteryCurrentAvgPath);
if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
mHealthInfo->batteryChargeTimeToFullNowSeconds =
getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
mHealthInfo->batteryFullChargeDesignCapacityUah =
getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
props.batteryTemperature = mBatteryFixedTemperature ?
mBatteryFixedTemperature :
getIntField(mHealthdConfig->batteryTemperaturePath);
std::string buf;
if (readFromFile(mHealthdConfig->batteryCapacityLevelPath, &buf) > 0)
mHealthInfo->batteryCapacityLevel = getBatteryCapacityLevel(buf.c_str());
if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
props.batteryStatus = getBatteryStatus(buf.c_str());
if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
props.batteryHealth = getBatteryHealth(buf.c_str());
if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
props.batteryTechnology = String8(buf.c_str());
double MaxPower = 0;
for (size_t i = 0; i < mChargerNames.size(); i++) {
String8 path;
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
if (getIntField(path)) {
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
props.chargerAcOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_USB:
props.chargerUsbOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
props.chargerWirelessOnline = true;
break;
default:
KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
mChargerNames[i].string());
}
path.clear();
path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
int ChargingCurrent =
(access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
path.clear();
path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
int ChargingVoltage =
(access(path.string(), R_OK) == 0) ? getIntField(path) :
DEFAULT_VBUS_VOLTAGE;
double power = ((double)ChargingCurrent / MILLION) *
((double)ChargingVoltage / MILLION);
if (MaxPower < power) {
props.maxChargingCurrent = ChargingCurrent;
props.maxChargingVoltage = ChargingVoltage;
MaxPower = power;
}
}
}
}
服务初始化函数void BatteryMonitor::init函数:
void BatteryMonitor::init(struct healthd_config *hc) {
String8 path;
char pval[PROPERTY_VALUE_MAX];
...
mHealthdConfig = hc;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
if (dir == NULL) {
KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
} else {
struct dirent* entry;
while ((entry = readdir(dir.get()))) {
const char* name = entry->d_name;
std::vector<String8>::iterator itIgnoreName;
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :INIT 111 name %s\n",name);
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
itIgnoreName = find(hc->ignorePowerSupplyNames.begin(),
hc->ignorePowerSupplyNames.end(), String8(name));
if (itIgnoreName != hc->ignorePowerSupplyNames.end())
continue;
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :INIT 222 name %s\n",name);
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :INIT 333 readPowerSupplyType %d\n",readPowerSupplyType(path));
switch(readPowerSupplyType(path)) {
...
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :INIT 333 name %s\n",name);
if (isScopedPowerSupply(name)) continue;
mBatteryDevicePresent = true;
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :INIT 444 name %s\n",name);
if (mHealthdConfig->batteryStatusPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryStatusPath = path;
}
if (mHealthdConfig->batteryHealthPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryHealthPath = path;
}
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :mHealthdConfig->batteryPresentPath %s\n",mHealthdConfig->batteryPresentPath.string());
if (mHealthdConfig->batteryPresentPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0){
mHealthdConfig->batteryPresentPath = path;
KLOG_WARNING(LOG_TAG, "BM xmhxj debug : %s/%s/present ok\n",POWER_SUPPLY_SYSFS_PATH,name);
} else {
KLOG_WARNING(LOG_TAG, "BM xmhxj debug : %s/%s/present fail \n",POWER_SUPPLY_SYSFS_PATH,name);
}
}
KLOG_WARNING(LOG_TAG, "BM xmhxj debug :init batteryPresentPath : %s \n",mHealthdConfig->batteryPresentPath.c_str());
...
if (!mBatteryDevicePresent) {
KLOG_WARNING(LOG_TAG, "No battery devices found\n");
hc->periodic_chores_interval_fast = -1;
hc->periodic_chores_interval_slow = -1;
} else {
...
}
vendor\mediatek\proprietary\external\libshowlogo 充电图片显示服务代码 最终调用void show_battery_capacity(unsigned int capacity)函数为电量显示时调用。
现象
log分析
抓取的异常串口log分析:
[ 4.746224][ T165] init: BOOTPROF: 4746.206241:INIT:init
[ 4.803653][ T1] init: init 6: [4801][0]processing action (charger) from (/system/etc/init/hw/init.rc:1093)
[ 4.805786][ T1] init: init 21: [4801][0]starting service 'kpoc_charger'...
[ 4.816035][ T1] init: init 21: [4801][0]starting service 'health-hal-2-1'...
[ 4.817246][ T1] init: init 21: [4801][0]Opened file '/dev/kmsg', flags 1
[ 4.829566][ T1] init: init 21: [4828][0]processing action (charger) from (/vendor/etc/init/hw/init.mt8168.rc:71)
[ 4.895068][ T1] init: init 21: [4892][0]Command 'write /sys/bus/platform/devices/battery/FG_daemon_log_level 7' action=charger (/vendor/etc/init/hw/init.mt8168.rc:96) took 1ms and failed: Unable to write to file '/sys/bus/platform/devices/battery/FG_daemon_log_level': open() failed: Permission denied
[ 4.900952][ T1] init: init 21: [4900][0]processing action (charger) from (/vendor/etc/init/hw/init.mt8168.usb.rc:73)
[ 4.925939][ T206] android.hardwar: healthd: BM xmhxj debug :INIT 111 name .
[ 4.926948][ T206] android.hardwar: healthd: BM xmhxj debug :INIT 111 name ..
[ 4.927952][ T206] android.hardwar: healthd: No battery devices found
[ 4.932247][ T1] init: init 21: [4931][0]processing action (charger) from (/vendor/etc/init/hw/init.project.rc:58)
[ 4.935972][ T1] init: init 21: [4934][0]starting service 'fuelgauged'...
[ 4.937344][ T206] health@2.1-serv: healthd: BM xmhxj debug :mHealthdConfig->batteryPresentPath.isEmpty() 1
[ 4.938631][ T206] health@2.1-serv: healthd: BM xmhxj debug :mHealthdConfig->batteryPresentPath
[ 4.939981][ T163] init: init 23: [4939][8]ReapLogT PropSet [sys.usb.configfs]=[0]4738 [sys.lmk.reportkills]=[1]4740 [init.svc.kpoc_charger]=[running]4812 [ro.boottime.kpoc_charger]=[4808788307]4813 [init.svc_debug_pid.kpoc_charger]=[204]4813 [init.svc.health-hal-2-1]=[running]4826 [ro.boottime.health-hal-2-1]=[4824270692]4827 [init.svc_debug_pid.health-hal-2-1]=[206]4828 [hwservicemanager.ready]=[true]4912 [sys.usb.configfs]=[1]4923 [sys.usb.controller]=[11201000.usb]4924 [vendor.usb.acm_cnt]=[0]4926 [vendor.usb.acm_port0]=[]4927 [vendor.usb.acm_port1]=[]4928 [vendor.usb.acm_enable]=[0]4928 [vendor.usb.clear]=[boot]4929 [sys.usb.config]=[hid]4930 Done
[ 4.944828][ T206] health@2.1-serv: healthd: BM xmhxj debug : mHealthdConfig->batteryPresentPath.isEmpty() mBatteryDevicePresent 0
[ 4.948799][ T206] health@2.1-serv: healthd: BM xmhxj debug : props.batteryPresent 0
[ 4.949877][ T206] health@2.1-serv: healthd: xmhxj debug : battery none chg=
[ 4.950707][ T1] init: init 6: [4948][0]starting service 'fuelgauged_nvram'...
[ 4.950816][ T206] health@2.1-serv: healthd: BM xmhxj debug :mHealthdConfig->batteryPresentPath.isEmpty() 1
从log中可以知道初始化时获取power_supply节点下的信息为空
[ 4.925939][ T206] android.hardwar: healthd: BM xmhxj debug :INIT 111 name .
[ 4.926948][ T206] android.hardwar: healthd: BM xmhxj debug :INIT 111 name ..
[ 4.927952][ T206] android.hardwar: healthd: No battery devices found
[ 4.937344][ T206] health@2.1-serv: healthd: BM xmhxj debug :mHealthdConfig->batteryPresentPath.isEmpty() 1
导致
health@2.1-serv: healthd: xmhxj debug : battery none chg=
使得关机充电时充电信息的获取无法从healthd中得到。使得加载为0%
而比较正常的开机log为:
[ 12.834990][ T1] init: init 23: [12681][0]starting service 'health-hal-2-1'...
...
[ 13.094853][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 111 name .
[ 13.095843][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 111 name ..
[ 13.096817][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 111 name mtk-gauge
[ 13.123017][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 222 name mtk-gauge
[ 13.124642][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 333 readPowerSupplyType 0
[ 13.145360][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 111 name battery
[ 13.146437][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 222 name battery
[ 13.170693][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 333 readPowerSupplyType 4
[ 13.172061][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 333 name battery
[ 13.205482][ T426] android.hardwar: healthd: BM xmhxj debug :INIT 444 name battery
对策
在void BatteryMonitor::init(struct healthd_config hc)初始化函数中添加延迟 具体修改如下:
void BatteryMonitor::init(struct healthd_config *hc) {
String8 path;
char pval[PROPERTY_VALUE_MAX];
+
+ nsecs_t now;
+ nsecs_t start_t;
+ now = nanoseconds_to_seconds(systemTime());
+ KLOG_WARNING(LOG_TAG, " BM xmhxj debug :now %ld\n", (long)now);
+
+ while((nanoseconds_to_seconds(systemTime()) <= 15 ));
+ start_t = nanoseconds_to_seconds(systemTime());
+ KLOG_WARNING(LOG_TAG, " BM xmhxj debug : start_t %ld\n", (long)start_t);
+ KLOG_WARNING(LOG_TAG, " BM xmhxj debug : 222 now %ld\n", (long)(start_t - now));
mHealthdConfig = hc;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
if (dir == NULL) {
...
}
截取log如下:
Line 2872: [ 5.034645][ T195] android.hardwar: healthd: BM xmhxj debug :now 5
Line 5280: [ 16.001043][ T195] android.hardwar: healthd: BM xmhxj debug : start_t 16
Line 5281: [ 16.001955][ T195] android.hardwar: healthd: BM xmhxj debug : 222 now 11
Line 5282: [ 16.003457][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 111 name .
Line 5283: [ 16.004371][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 111 name ..
Line 5284: [ 16.005314][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 111 name mtk-gauge
Line 5285: [ 16.006321][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 222 name mtk-gauge
Line 5286: [ 16.007688][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 333 readPowerSupplyType 0
Line 5287: [ 16.008824][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 111 name battery
Line 5288: [ 16.009910][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 222 name battery
Line 5289: [ 16.011025][ T195] android.hardwar: healthd: BM xmhxj debug :INIT 333 readPowerSupplyType 4
总结
由于项目创建时的一些客制化修改导致关机充电服务过早的被调用,而底层kernel中的power_supply相关的节点设备(battery)等还未初始化注册,使得上层的初始化时读取的power_supply下的节点为空导致。解决方式为:在上层的初始化中添加延迟等待,模拟到正常开机时调用的时刻再执行节点设备获取。
本人有道笔记记录同步: 1:http://note.youdao.com/noteshare?id=418b40be3ff208d70cc80b9ff3f21b55&sub=8751EEB0DD0E47A28ADD474328B26DC6
|