MTK平台BUG解决:客户电池NTC功能
- 一、概述
- 二、步骤
- 1:实现目的?
- 2:准备工作:机制原理的学习
- (1)MTK充电温度保护机制
- (2)MTKthermal高温充电机制
- 3:定位查找与源码分析
- (1)根据充电温度保护机制kernel层:
- (2)顺而在与(1)***同目录下的mtk_charger.h***文件中
- (3)根据充电温度保护机制frameworks层发送广播:
- (4)根据充电温度保护机制app层接收广播文件:
- 4:源码详细分析(可暂时跳过)
- (1)BatteryWarningReceiver.java
- (2)BatteryWarningActivity.java
- (3)ThermalWarningActivity
- (4)batterywarning.cpp
- 5:目标功能实现推理与复盘
- 6:提出对应解决方案
- 7:解决实现
- (1) 代码修改-
- (2) 检查代码-
- (3) 编译代码:
- (4) 打包代码
- (5) 测试:
一、概述
首先我也是第一次收到这个类型的BUG任务,作为Android开发初学者分享一下解决BUG实现相关内容的完整且详细的解决步骤,首先搞清楚问题是什么,目的要干嘛?然后需要做什么准备,有一个大致的定位思路,其次遇到问题思考问题,注意逻辑性、连贯性,再者保持记录与分析,最后得出结果后倒推实现逻辑与复盘,最最后修改代码、检查代码、编译、打包、测试。
二、步骤
1:实现目的?
BUG中描述需要研发人员安排研发移植高低温报警,关机报警功能,具体表现为:
手机充电过程中,
- 手机温度达47度时,需要将手机充电电流降低到800毫安
- 手机温度达60度时,需要有提示语来提示手机温度过高并停止充电
- 手机温度达65度时,需要有提示语来提示手机温度过高并手机关机
而需要我去修改的主要是2,3点
对此,需要思考电池NTC报警机制和温升控制机制在哪里实现,机制原理是什么?
进而首先要学习机制原理,然后定位电量预警控制相关源码文件内容,分析源码,串联逻辑。
2:准备工作:机制原理的学习
(1)MTK充电温度保护机制
- kernel层充电温度保护机制:kernel\kernel-5.15\drivers\power\supply目录下的mtk_charger.c中编写了充电保护线程内容
- frameworks层发送广播vendor/mediatek/proprietary/frameworks/opt/batterywarning/batterywarning.cpp
- app层接收广播vendor/mediatek/proprietary/packages/apps/BatteryWarning/src/com/mediatek/batterywarning/BatteryWarningReceiver.java中onCreate()方法判断当mType类型在0-5之间,就调用showWarningDialog()弹出提醒框
(2)MTKthermal高温充电机制
thermal主要由thermal配置文件和thermal的驱动代码进行控制(我描述的简略,更多另外查询)
3:定位查找与源码分析
(1)根据充电温度保护机制kernel层:
kernel\kernel-5.15\drivers\power\supply\mtk_charger.c文件中,
浏览检索到关键词MAX_CHARGE_TEMP,即最高充电温度,
(2)顺而在与(1)同目录下的mtk_charger.h文件中
找到了关键词的自定义值为50,推理此时手机充电电池温度达到50度即发出报警提示与其他操作。
(3)根据充电温度保护机制frameworks层发送广播:
vendor/mediatek/proprietary/frameworks/opt/batterywarning/batterywarning.cpp文件中,
batterywarning.cpp中有一个readType方法里有一个条件判断语句,如下图,会根据type的值来输出不同的日志信息并发送广播,由下,又定位到接收广播的文件:
app层接收广播的文件路径:
\vendor\mediatek\proprietary\packages\apps\BatteryWarning\src\com\mediatek\batterywarning\BatteryWarningActivity.java
这个文件中可以看到有type含义类型:
由此可知当BATTERY_OVER_TEMPERATURE_TYPE = 1即为电池温度过高,所以
需要知道相关方法中条件句中判断type值为1时会执行哪些操作。
在***\frameworks\base\services\core\java\com\android\server\BatteryService.java文件中有个shutdownIfOverTempLocked方法*,
如下:
这个方法意思是如果温度过高就关机,注释中也描述了当温度过高大于68摄氏度时关机,
其中判断语句中的mShutdownBatteryTemperature为默认关机电池温度,
在本文件中搜索关键词mShutdownBatteryTemperature定位到:
可知mShutdownBatteryTemperature取值于名为config_shutdownBatteryTemperature的整型变量,即默认配置关机电池温度,
在终端中使用grep命令搜索config_shutdownBatteryTemperature关键词出现在
\frameworks\base\core\res\res\values\config.xml配置文件中,config.xml文件中config_shutdownBatteryTemperature如下图:
(4)根据充电温度保护机制app层接收广播文件:
vendor/mediatek/proprietary/packages/apps/BatteryWarning/src/com/mediatek/batterywarning/BatteryWarningReceiver.java
在BatteryWarningReceiver.java中分析可知该Java代码主要涉及启动BatteryWarningActivity和ThermalWarningActivity。
BatteryWarningActivity和ThermalWarningActivity的文件路径分别在:
- vendor\mediatek\proprietary\packages\apps\BatteryWarning\src\com\mediatek\batterywarning\BatteryWarningActivity.java
用于在电池电量过低时提醒用户 - vendor\mediatek\proprietary\packages\apps\BatteryWarning\src\com\mediatek\batterywarning\ThermalWarningActivity.java
用于在设备过热时提醒用户。
另外,BatteryWarningReceiver.java中还有一些其他操作,如清除SharedPreferences数据等。
BatteryWarningActivity.java在上一步已经分析,打开其同目录下的ThermalWarningActivity.java进行分析,
ThermalWarningActivity.java整段代码的功能:
在温度过高时显示一个警告对话框,并提供一个确定按钮供用户关闭对话框。具体实现是在onCreate方法中获取传递过来的type值,并调用showWarningDialog方法设置对话框的文本信息和按钮监听器。showWarningDialog方法中根据传递过来的type值设置对话框中的文本信息和按钮监听器。当用户点击按钮时,调用finish方法关闭当前Activity。
4:源码详细分析(可暂时跳过)
我主要详细分析下面4份代码:(这一部分内容繁多,可跳过,不理解再查阅)
(1)BatteryWarningReceiver.java
源码如下:
package com.mediatek.batterywarning;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
public class BatteryWarningReceiver extends BroadcastReceiver {
// private static final String ACTION_IPO_BOOT = "android.intent.action.ACTION_BOOT_IPO";
private static final String ACTION_BATTERY_WARNING = "mediatek.intent.action.BATTERY_WARNING";
private static final String ACTION_BATTERY_NORMAL = "mediatek.intent.action.BATTERY_NORMAL";
private static final String TAG = "BatteryWarningReceiver";
private static final String SHARED_PREFERENCES_NAME = "battery_warning_settings";
private Context mContext;
private Context mDeviceContext;
// Thermal over temperature
private static final String ACTION_THERMAL_WARNING = "mediatek.intent.action.THERMAL_DIAG";
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
mDeviceContext = mContext.createDeviceProtectedStorageContext();
if (mDeviceContext == null) {
mDeviceContext = mContext;
}
String action = intent.getAction();
Log.d(TAG, "action = " + action);
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Log.d(TAG, action + " clear battery_warning_settings shared preference");
SharedPreferences.Editor editor = getSharedPreferences().edit();
editor.clear();
editor.apply();
} else if (ACTION_BATTERY_WARNING.equals(action)) {
Log.d(TAG, action + " start activity according to shared preference");
int type = intent.getIntExtra("type", -1);
Log.d(TAG, "type = " + type);
type = (int) (Math.log(type) / Math.log(2));
if (type < 0 || type >= BatteryWarningActivity.sWarningTitle.length) {
return;
}
boolean showDialogFlag = getSharedPreferences().getBoolean(
Integer.toString(type), true);
Log.d(TAG, "type = " + type + "showDialogFlag = " + showDialogFlag);
if (showDialogFlag) {
Intent activityIntent = new Intent();
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
activityIntent.setClass(mContext, BatteryWarningActivity.class);
activityIntent.putExtra(BatteryWarningActivity.KEY_TYPE, type);
mContext.startActivity(activityIntent);
}
} else if (ACTION_THERMAL_WARNING.equals(action)) {
int typeValue = intent.getIntExtra(ThermalWarningActivity.KEY_TYPE, -1);
Log.d(TAG, "typeValue = " + typeValue);
if (typeValue == 0 || typeValue == 1) {
Intent thermalIntent = new Intent();
thermalIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
thermalIntent.setClass(mContext, ThermalWarningActivity.class);
thermalIntent.putExtra(ThermalWarningActivity.KEY_TYPE, typeValue);
mContext.startActivity(thermalIntent);
}
} else if (ACTION_BATTERY_NORMAL.equals(action)) {
int type = intent.getIntExtra("type", -1);
int type1;
if(type==0)
{
type1=-1;
Intent activityIntent = new Intent();
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
activityIntent.setClass(mContext, BatteryWarningActivity.class);
activityIntent.putExtra(BatteryWarningActivity.KEY_TYPE, type1);
mContext.startActivity(activityIntent);
}
}
}
private SharedPreferences getSharedPreferences() {
return mDeviceContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
}
代码大体分析:
定义BatteryWarningReceiver类,继承BroadcastReceiver类
定义ACTION_BATTERY_WARNING字符串常量
定义ACTION_BATTERY_NORMAL字符串常量
定义TAG字符串常量,用于日志输出
定义SHARED_PREFERENCES_NAME字符串常量,用于SharedPreferences的名称
定义mContext和mDeviceContext变量,分别表示应用的上下文和设备受保护存储区的上下文
定义ACTION_THERMAL_WARNING字符串常量
定义onReceive方法,用于接收广播并处理相应逻辑
将context赋值给mContext,并通过createDeviceProtectedStorageContext方法创建mDeviceContext
如果mDeviceContext为空,则将mContext赋值给mDeviceContext
获取广播的Action
如果广播的Action是ACTION_BOOT_COMPLETED,则清除SharedPreferences中的battery_warning_settings数据
如果广播的Action是ACTION_BATTERY_WARNING,则根据SharedPreferences中的设置,启动BatteryWarningActivity
如果广播的Action是ACTION_THERMAL_WARNING,则根据传递的参数,启动ThermalWarningActivity
如果广播的Action是ACTION_BATTERY_NORMAL,则根据传递的参数,启动BatteryWarningActivity
定义getSharedPreferences方法,用于获取SharedPreferences对象
整段代码的功能是:接收广播并根据广播的Action执行相应的操作,主要涉及启动BatteryWarningActivity和ThermalWarningActivity。
其中,BatteryWarningActivity用于在电池电量过低时提醒用户,
ThermalWarningActivity用于在设备过热时提醒用户。
另外,还有一些其他操作,如清除SharedPreferences数据等。
(2)BatteryWarningActivity.java
源码如下:
package com.mediatek.batterywarning;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
public class BatteryWarningActivity extends Activity {
private static final String TAG = "BatteryWarningActivity";
public static final String WARNING_NOTIFICATION_CHANNEL_ID = "battery_warning_notif_channel";
private static final Uri WARNING_SOUND_URI = Uri
.parse("file:///system/media/audio/ui/VideoRecord.ogg");
private static final String SHARED_PREFERENCES_NAME = "battery_warning_settings";
protected static final String KEY_TYPE = "type";
private static boolean mWaterGas =false;
private Ringtone mRingtone;
private int mType;
private static final int CHARGER_OVER_VOLTAGE_TYPE = 0;
private static final int BATTERY_OVER_TEMPERATURE_TYPE = 1;
private static final int CURRENT_OVER_PROTECTION_TYPE = 2;
private static final int BATTERY_OVER_VOLTAGE_TYPE = 3;
private static final int SAFETY_OVER_TIMEOUT_TYPE = 4;
private static final int BATTERY_LOW_TEMPERATURE_TYPE = 5;
private static final int TYPEC_DETECTION_WATER_GAS_TYPE = 6;
static final int[] sWarningTitle = new int[] {
R.string.title_charger_over_voltage,
R.string.title_battery_over_temperature,
R.string.title_over_current_protection,
R.string.title_battery_over_voltage,
R.string.title_safety_timer_timeout,
R.string.title_battery_low_temperature,
R.string.title_typeC_detection_water_gas
};
private static final int[] sWarningMsg = new int[] {
R.string.msg_charger_over_voltage,
R.string.msg_battery_over_temperature,
R.string.msg_over_current_protection,
R.string.msg_battery_over_voltage,
R.string.msg_safety_timer_timeout,
R.string.msg_battery_low_temperature,
R.string.msg_typeC_detection_water_gas };
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
if (mType == CHARGER_OVER_VOLTAGE_TYPE
|| mType == SAFETY_OVER_TIMEOUT_TYPE || mType == BATTERY_LOW_TEMPERATURE_TYPE) {
Log.d(TAG, "receive ACTION_POWER_DISCONNECTED broadcast, finish");
finish();
}
}
}
};
public static void initWarningNotificationChannel(Context context) {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// BatteryWarning Notification Channel
CharSequence name = "Battery Warning";
NotificationChannel mChannelBatWarn = new NotificationChannel(
WARNING_NOTIFICATION_CHANNEL_ID,
name,
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(mChannelBatWarn);
Log.d(TAG, "initWarningNotificationChannel " + mChannelBatWarn);
}
public static void deleteWarningNotificationChannel(Context context, String channelId) {
Log.d(TAG, "deleteWarningNotificationChannel " + channelId);
NotificationManager notificationManager = (NotificationManager) context.
getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.deleteNotificationChannel(channelId);
}
public void showBatteryWarningNotification(Context context) {
String title="";
String content="";
title = getString(R.string.notification_title);
content= getString(R.string.notification_wd_text);
NotificationManager notificationManager = (NotificationManager) context.
getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = new Notification.Builder(context, WARNING_NOTIFICATION_CHANNEL_ID)
.setContentTitle(title)
.setContentText(content)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setSound(null)
.setOngoing(true)
.build();
notificationManager.notify(0, notif);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
Context context;
context=BatteryWarningActivity.this;//this.getApplicationContext();
setContentView(R.layout.battery_warning);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
R.layout.custom_title_1);
Intent intent = getIntent();
mType = intent.getIntExtra(KEY_TYPE, -1);
TextView textView = (TextView) findViewById(R.id.left_text);
Log.d(TAG, "onCreate, mType is " + mType);
if (mType >= CHARGER_OVER_VOLTAGE_TYPE && mType <= TYPEC_DETECTION_WATER_GAS_TYPE) {
textView.setText(getString(sWarningTitle[mType]));
if(mType==TYPEC_DETECTION_WATER_GAS_TYPE)
{
initWarningNotificationChannel(context);
showBatteryWarningNotification(context);
mWaterGas =true;
} else {
deleteWarningNotificationChannel(context,WARNING_NOTIFICATION_CHANNEL_ID);
mWaterGas = false;
}
showWarningDialog(mType);
registerReceiver(mReceiver, new IntentFilter(
Intent.ACTION_POWER_DISCONNECTED));
} else {
if(mWaterGas) {
deleteWarningNotificationChannel(context,WARNING_NOTIFICATION_CHANNEL_ID);
mWaterGas = false;
}
finish();
}
}
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy, stopRingtone");
stopRingtone();
if (mType >= CHARGER_OVER_VOLTAGE_TYPE && mType <= TYPEC_DETECTION_WATER_GAS_TYPE) {
unregisterReceiver(mReceiver);
}
}
private void showWarningDialog(int type) {
TextView textView = (TextView) findViewById(R.id.text);
textView.setText(getString(sWarningMsg[mType]));
LinearLayout layout = (LinearLayout)findViewById(R.id.inner_content);
if(type!= TYPEC_DETECTION_WATER_GAS_TYPE) {
ImageView iv = new ImageView(BatteryWarningActivity.this);
iv.setImageDrawable(getResources().getDrawable(R.drawable.battery_low_battery));
iv.setPadding(4, 4, 4, 4);
layout.addView(iv);
}
Button button = (Button)findViewById(R.id.add);
button.setText(getString(R.string.btn_cancel_msg));
button.setOnClickListener(mDismissContentListener);
button = (Button)findViewById(R.id.remove);
button.setText(getString(R.string.btn_ok_msg));
button.setOnClickListener(mSnoozeContentListener);
playAlertSound(WARNING_SOUND_URI);
}
private OnClickListener mDismissContentListener = new OnClickListener() {
public void onClick(View v) {
stopRingtone();
SharedPreferences.Editor editor = getSharedPreferences().edit();
editor.putBoolean(Integer.toString(mType), false);
editor.apply();
Log.d(TAG, "set type " + mType + " false");
finish();
}
};
private OnClickListener mSnoozeContentListener = new OnClickListener() {
public void onClick(View v) {
stopRingtone();
finish();
}
};
/**
*
* @param context
* The Context that had been passed to
* {@link #warningMessageDialog(Context, Uri)}
* @param defaultUri
*/
private void playAlertSound(Uri defaultUri) {
if (defaultUri != null) {
mRingtone = RingtoneManager.getRingtone(this, defaultUri);
if (mRingtone != null) {
mRingtone.setStreamType(AudioManager.STREAM_SYSTEM);
mRingtone.play();
}
}
}
private void stopRingtone() {
if (mRingtone != null) {
mRingtone.stop();
mRingtone = null;
}
}
private SharedPreferences getSharedPreferences() {
return getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
}
代码大体分析:
这段Java代码是一个Android应用程序中的Activity类,主要实现响应电池异常告警事件的处理。
类的属性定义,主要是定义了一些静态变量,如日志的TAG,告警通知音效的uri,告警通知渠道ID,异常类型等,还有成员变量,如Ringtone实例、Context实例、告警类型等。
定义了一个名为mReceiver的内部广播接收器,主要处理电源断开事件。
静态方法initWarningNotificationChannel,用于在Android系统的通知管理器中创建通知渠道。
静态方法deleteWarningNotificationChannel,用于删除通知渠道。
成员方法showBatteryWarningNotification,用于显示电池告警通知。
该Activity类的onCreate()方法,主要根据接收到的电池异常告警类型展示相应的对话框,还处理了电源断开事件和销毁Activity时的一些操作。
该类的onDestroy()方法,处理Activity销毁后的一些操作,如停止铃声播放和注销广播接收器等。
该类的showWarningDialog方法,显示告警对话框,包括告警类型、告警内容、告警图片和两个按钮(一个取消,一个确定)。
该类的playAlertSound方法,用于播放告警音效。 该类的stopRingtone方法,用于停止告警音效播放。
该类的getSharedPreferences方法,获取应用程序的SharedPreferences对象。
总体来说,该Activity类主要实现了电池异常告警功能,包括通知、动态创建通知渠道、告警对话框的显示和电源断开的处理。
(3)ThermalWarningActivity
源码如下:
package com.mediatek.batterywarning;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
/**
* ThermalWarningActivity: show warning dialog when thermal is over temperature.
*/
public class ThermalWarningActivity extends Activity {
private static final String TAG = "ThermalWarningActivity";
protected static final String KEY_TYPE = "type";
private static final int[] sWarningMsg = new int[] { R.string.thermal_clear_temperature,
R.string.thermal_over_temperature };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
int type = intent.getIntExtra(KEY_TYPE, -1);
Log.d(TAG, "onCreate, type is " + type);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.thermal_warning);
showWarningDialog(type);
}
private void showWarningDialog(int type) {
TextView mMessageView = (TextView) findViewById(R.id.text);
mMessageView.setText(getString(sWarningMsg[type]));
Button button = (Button) findViewById(R.id.yes);
button.setText(getString(android.R.string.yes));
button.setOnClickListener(mYesContentListener);
}
private OnClickListener mYesContentListener = new OnClickListener() {
public void onClick(View v) {
finish();
}
};
}
代码大体分析:
导入需要使用的Android类。 声明一个名为ThermalWarningActivity的类,继承自Activity类。
定义TAG常量和KEY_TYPE常量。 定义一个整型数组sWarningMsg,用于存储两个警告信息的资源ID。
重写onCreate方法,在该方法中获取传递过来的type值,并调用showWarningDialog方法显示警告对话框。
定义showWarningDialog方法,根据传递过来的type值设置对话框中的文本信息和按钮监听器。
定义mYesContentListener匿名内部类,实现OnClickListener接口,当用户点击按钮时调用finish方法关闭当前Activity。
整段代码的功能是:在温度过高时显示一个警告对话框,并提供一个确定按钮供用户关闭对话框。具体实现是在onCreate方法中获取传递过来的type值,并调用showWarningDialog方法设置对话框的文本信息和按钮监听器。showWarningDialog方法中根据传递过来的type值设置对话框中的文本信息和按钮监听器。当用户点击按钮时,调用finish方法关闭当前Activity。
(4)batterywarning.cpp
源码如下:
#define LOG_TAG "batterywarning"
#include <stdio.h>
#include <stdlib.h>
#include <utils/Log.h>
#include <utils/String16.h>
#include <binder/BinderService.h>
#include <binder/Parcel.h>
#include <cutils/uevent.h>
#include <sys/epoll.h>
#include <errno.h>
#define MAX_CHAR 100
//M: Currently disabling battery path.. in later stage we will update in code to check path by order. @{
//#ifdef MTK_GM_30
//#define FILE_NAME "/sys/devices/platform/charger/BatteryNotify"
//#else
//#define FILE_NAME "/sys/devices/platform/mt-battery/BatteryNotify"
//#endif
//M: @}
#define ACTION "mediatek.intent.action.BATTERY_WARNING"
#define NORMAL_ACTION "mediatek.intent.action.BATTERY_NORMAL"
#define TYPE "type"
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
using namespace android;
#define MAX_EPOLL_EVENTS 40
static int uevent_fd;
static int epollfd;
static int eventct;
bool sendBroadcastMessage(String8 action, int value)
{
ALOGD("sendBroadcastMessage(): Action: %s, Value: %d ", (char *)(action.string()), value);
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> am = sm->getService(String16("activity"));
if (am != NULL) {
Parcel data, reply;
data.writeInterfaceToken(String16("android.app.IActivityManager"));
data.writeStrongBinder(NULL);
// Add for match AMS change on O
data.writeInt32(1);
// intent begin
data.writeString8(action); // action
data.writeInt32(0); // URI data type
data.writeString8(NULL, 0); // type
data.writeString8(NULL, 0); // mIdentifier
data.writeInt32(0x04000000); // flags: FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
data.writeString8(NULL, 0); // package name
data.writeString8(NULL, 0); // component name
data.writeInt32(0); // source bound - size
data.writeInt32(0); // categories - size
data.writeInt32(0); // selector - size
data.writeInt32(0); // clipData - size
data.writeInt32(-2); // contentUserHint: -2 -> UserHandle.USER_CURRENT
data.writeInt32(-1); // bundle extras length
data.writeInt32(0x4C444E42); // 'B' 'N' 'D' 'L'
int oldPos = data.dataPosition();
data.writeInt32(1); // size
// data.writeInt32(0); // VAL_STRING, need to remove because of analyze common intent
data.writeString16(String16(TYPE));
data.writeInt32(1); // VAL_INTEGER
data.writeInt32(value);
int newPos = data.dataPosition();
data.setDataPosition(oldPos - 8);
data.writeInt32(newPos - oldPos); // refill bundle extras length
data.setDataPosition(newPos);
data.writeInt32(0);
// intent end
data.writeString8(NULL, 0); // resolvedType
data.writeStrongBinder(NULL); // resultTo
data.writeInt32(0); // resultCode
data.writeString8(NULL, 0); // resultData
data.writeInt32(-1); // resultExtras
data.writeString8(NULL, 0); // permission
data.writeInt32(0); // appOp
data.writeInt32(-1); // option
data.writeInt32(1); // serialized: != 0 -> ordered
data.writeInt32(0); // sticky
data.writeInt32(-2); // userId: -2 -> UserHandle.USER_CURRENT
status_t ret = am->transact(IBinder::FIRST_CALL_TRANSACTION + 14, data, &reply); // BROADCAST_INTENT_TRANSACTION
if (ret == NO_ERROR) {
int exceptionCode = reply.readExceptionCode();
if (exceptionCode) {
ALOGE("sendBroadcastMessage(%s) caught exception %d\n",
(char *)(action.string()), exceptionCode);
return false;
}
} else {
return false;
}
} else {
ALOGE("getService() couldn't find activity service!\n");
return false;
}
return true;
}
static const char *charger_file_path[] = {
"/sys/devices/platform/charger/BatteryNotify",
"/sys/devices/platform/mt-battery/BatteryNotify",
};
static int read_from_file(const char* path) {
if(!path) {
return 0;
}
int fd =open(path,O_RDONLY);
if(fd<0) {
close(fd);
return 0;
}
else {
close(fd);
return 1;
}
}
int get_charger_file_path() {
int i = 0;
for(i=0;i<ARRAY_SIZE(charger_file_path);i++) {
if(read_from_file(charger_file_path[i])) {
return i;
}
}
return 0;
}
void readType(char* buffer) {
FILE * pFile;
int file_index;
file_index=get_charger_file_path();
ALOGD("Inside file_index value : %d\n", file_index);
pFile = fopen(charger_file_path[file_index], "r");
if (pFile == NULL) {
ALOGE("error opening file");
return;
} else {
if (fgets(buffer, MAX_CHAR, pFile) == NULL) {
fclose(pFile);
ALOGE("can not get the string from the file");
return;
}
}
fclose(pFile);
int type = atoi(buffer);
if (type==0)
{
ALOGD("start activity by send intent to BatteryWarningReceiver to remove notification, type = %d\n", type);
sendBroadcastMessage(String8(NORMAL_ACTION), type);
}
if (type > 0)
{
ALOGD("start activity by send intent to BatteryWarningReceiver, type = %d\n", type);
sendBroadcastMessage(String8(ACTION), type);
}
}
#define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/) {
char msg[UEVENT_MSG_LEN + 2];
char *cp;
char *status;
int n;
char *buffer = (char*) malloc(MAX_CHAR * sizeof(char));
if (buffer == NULL) {
ALOGD("malloc memory failed");
return ;
}
n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0) return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n + 1] = '\0';
cp = msg;
while (*cp) {
if (!strncmp(cp, "CHGSTAT=", strlen("CHGSTAT="))) { // This CHGSTAT value will be provided by kernel driver
readType(buffer);
break;
}
/* advance to after the next \0 */
while (*cp++)
;
}
free(buffer);
}
int batterywarn_register_event(int fd, void (*handler)(uint32_t)) {
struct epoll_event ev;
ev.events = EPOLLIN;
//if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
ev.data.ptr = (void*)handler;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
ALOGD("epoll_ctl failed; errno=%d\n", errno);
return -1;
}
return 0;
}
static void uevent_init(void) {
uevent_fd = uevent_open_socket(64 * 1024, true);
if (uevent_fd < 0) {
ALOGD("uevent_init: uevent_open_socket failed\n");
return;
}
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
if (batterywarn_register_event(uevent_fd, uevent_event))
ALOGD("register for uevent events failed\n");
}
static void batterywarn_mainloop(void) {
int nevents = 0;
while (1) {
struct epoll_event events[1];
nevents = epoll_wait(epollfd, events, 1, -1);
if (nevents == -1) {
if (errno == EINTR) continue;
ALOGD("batterywarn_mainloop: epoll_wait failed\n");
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr) (*(void (*)(int))events[n].data.ptr)(events[n].events);
}
}
return;
}
static int batterywarn_init() {
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1) {
ALOGD("epoll_create failed; errno=%d\n", errno);
return -1;
}
uevent_init();
return 0;
}
int main()
{
char *buffer = (char*) malloc(MAX_CHAR * sizeof(char));
if (buffer == NULL) {
ALOGD("malloc memory failed");
return 0;
}
int ret;
/* Read the status to catch the event when batterywarning is not started */
readType(buffer);
ret= batterywarn_init();
if (ret) {
ALOGD("Initialization failed, exiting\n");
exit(1);
}
batterywarn_mainloop();
free(buffer);
return 0;
}
代码大体分析:
首先sendBroadcastMessage,这是一段用于发送广播消息的代码:定义了一个名为sendBroadcastMessage的函数,它接受两个参数:一个字符串类型的action和一个整型的value,并返回一个布尔类型的值。使用ALOGD函数记录日志,显示传入函数的action和value参数,以便调试和诊断。创建一个sp对象sm并将其初始化为默认服务管理器。使用getService方法从sm中获取一个名为“activity”的服务管理器。判断是否成功获取到了服务管理器am。如果获取到了,就进行下一步操作。如果获取不到则直接返回false。创建一个Parcel对象data,并在其中写入广播消息的不同参数和数据。其中最重要的是在第23-34行里写入了广播的内容值。在这里,action参数被写入到data对象的固定位置,value参数被打包到一个Bundle对象中。这个data对象最终传递给服务管理器am。通过调用am的transact方法向系统发送广播消息并读取回复。在这个过程中,如果出现异常,则捕获并记录错误信息,返回false。如果一切顺利则返回true。
然后定义了一个名为charger_file_path的静态常量字符指针数组,
定义了一个名为read_from_file的静态整型函数,
定义了一个名为get_charger_file_path的整型函数,
然后readType方法里:根据 type 的值进行不同的处理输出日志信息并发送广播。
后面的代码主要包含了对系统电池状态的监控和事件处理的功能
5:目标功能实现推理与复盘
这里不多赘述,主要是通过前面分析的内容去再一步的理清逻辑关系,然后具体分析源码内容以达到更完整的了解
6:提出对应解决方案
此时对温控保护机制温升策略的内容在不同层面已经有了一定了解,已知电池温度type为温度过高时会弹出报警提示及其相关操作,同时知道了mtk_charger.h文件中自定义了最高充电温度,在config.xml配置文件中配置了停机电池温度,针对目的的解决方案为:
①kernel层充电温度保护机制:
drivers/power/supply/mediatek/charger/mtk_charger.h中设置了
MAX_CHARGE_TEMP 50,即50度为最高充电温度
将50修改为60。
②在frameworks\base\core\res\res\values\config.xml配置文件中修改配置停机电池温度:
680默认停机电池温度为68摄氏度,
改为650停机电池温度为65摄氏度。
7:解决实现
(1) 代码修改-
解决方案中已包括
(2) 检查代码-
修改代码完成后保存,在终端使用git status命令查看修改状态
(3) 编译代码:
该MTK_6769平台,先编译A12部分,再编译A13部分,编译成正式软件版本将编译语句中的userdebug改成user。
A13部分:./MSSI_COPY_Make AGN_2263RD_DS12848_T user
A12部分:python vendor/mediatek/proprietary/scripts/releasetools/split_build_helper.py
–run full_AGN_2263RD_DS12848_T-user --layers vnd 2>&1 |tee total_build1.log
(4) 打包代码
在A13上:
python out_sys/target/product/mssi_64_cn/images/split_build.py --system-dir out_sys/target/product/mssi_64_cn/images --vendor-dir …/S/out/target/product/AGN_2263RD_DS12848_T/images --output-dir output_load
(5) 测试:
由于测试需要特定温度环境等条件,所以发布测试申请让专业的测试人员进行测试。