Android-MTK平台功能需求解决:客户电池NTC功能(高低温报警功能)--第1天分析与解决

6 篇文章 3 订阅

一、概述

首先我也是第一次收到这个类型的BUG任务,作为Android开发初学者分享一下解决BUG实现相关内容的完整且详细的解决步骤,首先搞清楚问题是什么,目的要干嘛?然后需要做什么准备,有一个大致的定位思路,其次遇到问题思考问题,注意逻辑性、连贯性,再者保持记录与分析,最后得出结果后倒推实现逻辑与复盘,最最后修改代码、检查代码、编译、打包、测试。

二、步骤

1:实现目的?

BUG中描述需要研发人员安排研发移植高低温报警,关机报警功能,具体表现为:
手机充电过程中,

  1. 手机温度达47度时,需要将手机充电电流降低到800毫安
  2. 手机温度达60度时,需要有提示语来提示手机温度过高并停止充电
  3. 手机温度达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) 测试:

由于测试需要特定温度环境等条件,所以发布测试申请让专业的测试人员进行测试。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值