Android-源码分析-MTK平台BUG解决:客户电池NTC功能(移植高低温报警,关机报警功能)---第一天分析与解决

news2024/12/23 16:46:48

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中描述需要研发人员安排研发移植高低温报警,关机报警功能,具体表现为:
手机充电过程中,

  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) 测试:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/628473.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

提高自动化测试效率 , WEB自动化框架的基础封装模块!

目录 前言 一、环境搭建 1. Python环境 2. Selenium安装 3. Chrome浏览器 二、基础封装模块介绍 1. 代码框架介绍 2. 使用示例 三、总结 前言 在软件测试中&#xff0c;WEB自动化测试已成为不可或缺的一部分。WEB自动化测试涉及到大量的代码编写&#xff0c;为了提高…

SUSTechPOINTS三维点云标注工具使用

官方地址&#xff1a;SUSTechPOINTS 官方中文教程 相关文章&#xff1a; OpenPCDet安装、使用方式及自定义数据集训练 安装 git clone https://github.com/naurril/SUSTechPOINTS cd SUSTechPOINTS pip install -r requirement.txt wget https://github.com/naurril/SUSTec…

【全栈开发】基于Spring BootVueAndroid扫码授权登录

文章目录 一、引言二、设计1、移动端&#xff08;Android&#xff09;&#xff08;1&#xff09;库&#xff08;2&#xff09;依赖&#xff08;3&#xff09;使用 2、前端&#xff08;Vue&#xff09;&#xff08;1&#xff09;库&#xff08;2&#xff09;使用 3、后端&#x…

Home Assistant-开源智能家居系统

Home Assistant&#xff08;以下简称HA&#xff09; 它是个开源的智能家居平台&#xff0c;一个系统平台软件&#xff0c;像TB 1.它把家中的智能家居设备整合到HA中&#xff0c;它能够接入的设备非常的多比如小米、博联、易微联、飞利浦、特斯拉…&#xff0c;也可以接入软件&…

Python远程连接Ubuntu20.4下的Mariadb数据库进行操作

文章目录 前言一、ubuntu20.4安装mariadb10.51、更换数据源2、安装mariadb3、设置密码4、设置管理用户5、设置远程登录6、修改端口 二、mariadb10.5建库建表创建数据库2.建表 三、Python代码及环境准备1、Python2、环境 四、总结五、参考资料 前言 环境&#xff1a; 1、Ubuntu2…

Chromium浏览器渗透测试工具EvilSelenium简单入门

EvilSelenium是一款基于Selenium的渗透测试工具&#xff0c;该工具基于武器化的Selenium实现其功能&#xff0c;可以帮助广大研究人员针对基于Chromium的浏览器进行安全分析和渗透测试。 功能介绍 1、通过autofill获取存储的凭证信息&#xff1b; 2、获取Cookie数据&#xf…

高考答题卡怎么被机器识别?基于OpenCV答题卡识别模拟-米尔ARM+FPGA异构开发板

本篇测评由优秀测评者“筑梦者与梦同行”提供。 01. 前言MYD-JX8MMA7SDK发布说明 根据下图文件内容可以知道myir-image-full系统支持的功能&#xff0c;其支持OpenCV&#xff0c;也就不用在格外安装相关驱动包等&#xff0c;省了很多事情。 02. MYD-JX8MMA7软件评估指南 本文…

Java中Object类常用的11个方法

Java中Object类常用的11个方法 先看下 Object 的类结构&#xff08;快捷键&#xff1a;alt7&#xff09;&#xff1a; 1. getClass 方法&#xff08;获取类的class对象。&#xff09; public final native Class<?> getClass();final 方法、获取对象的运行时 class …

学生成绩管理系统(PowerDesigner+MyEclipse+SQL Server)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;69学生 获取完整源码源文件论文报告数据库表等 系统中用户共有管理员、教师和学生三种&#xff0c;分别对应不同的权限。 管理员 &#xff08;1&#xff09;院系的开设&#xff1b; &#xff08;2&#xff09;教师基本信息…

VScode的插件和.json文件和快捷键

文章目录 1. 插件了解插件的配置的修改Remote DevelopmentFilter LineC/C 和 C intellisense&#xff08;弃用&#xff09;cpp-check-lint 2. VScode中的.json文件2.1 tasks.jsontasks.json文件的格式tasks.json文件中任务的配置arg参数选择 案例&#xff1a; 2.2 lauch.json参…

数字逻辑复习重点总结

文章目录 前言第一章第二章第三章第四章第五章第六章第七章&#xff1a;第八章总结 前言 因为要期末考试了所以就将知识点进行了总结&#xff0c;把期末要考的知识点分章节进行划分&#xff0c;以至于我能取得一个好成绩。 第一章 进制转换 8421码、2421码、余3码、格雷码&am…

Creating Serial Numbers (C#)

此示例展示如何使用Visual C#编写的Add-ins为文件数据卡生成序列号。 注意事项&#xff1a; SOLIDWORKS PDM Professional无法强制重新加载用.NET编写的Add-ins&#xff0c;必须重新启动所有客户端计算机&#xff0c;以确保使用Add-ins的最新版本。 SOLIDWORKS PDM Professio…

购买一套WMS仓储管理系统要多少钱

随着电商行业的快速发展&#xff0c;仓储物流行业也逐渐成为了人们关注的焦点。WMS仓储管理系统作为物流管理领域的重要工具&#xff0c;在提高仓库管理效率、降低运营成本方面具有重要作用。那么&#xff0c;购买一套WMS仓储管理系统要多少钱呢&#xff1f; 首先&#xff0c;我…

Vue开发实战(03)-组件化开发

对组件功能的封装&#xff0c;可以像搭积木一样开发网页。 Vue官方的示例图对组件化开发的形象展示。左边是一个网页&#xff0c;可以按照功能模块抽象成很多组件&#xff0c;这些组件就像积木一样拼接成网页。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直…

Lecture 21 Summarisation

目录 Extractive: Single-DocExtractive: Multi-DocAbstractive: Single-DocEvaluationConclusion summarisation Distill the most important information from a text to produce shortened or abridged versionExamples outlines of a documentabstracts of a scientific ar…

MapReduce【小文件的优化-Sequence文件】

在实际开发中&#xff0c;我们肯定希望提高MapReduce的工作效率&#xff0c;其实提高MapReduce的效率&#xff0c;无非就是提高Map阶段和Reduce阶段的效率。 Map阶段优化之小文件问题 我们知道Map阶段中的MapTask个数是与InputSplit的个数有关的&#xff0c;一般一个InputSpl…

《微服务实战》 第二十八章 分布式锁框架-Redisson

前言 Redisson 在基于 NIO 的 Netty 框架上&#xff0c;充分的利⽤了 Redis 键值数据库提供的⼀系列优势&#xff0c;在Java 实⽤⼯具包中常⽤接⼝的基础上&#xff0c;为使⽤者提供了⼀系列具有分布式特性的常⽤⼯具类。使得原本作为协调单机多线程并发程序的⼯具包获得了协调…

VR全景营销颠覆传统营销模式,让商企博“出圈”

在激烈的市场竞争中&#xff0c;营销成为了商企博“出圈”的重要课题&#xff0c;随着5G的到来&#xff0c;VR全景迈入了快速发展时期&#xff0c;随着VR全景的普及应用&#xff0c;商业领域也逐渐引入了VR全景营销。 时下&#xff0c;商企的营销是越发困难&#xff0c;传统的营…

币圈下半年重点之一:以太坊坎昆升级,将带来哪些实质性利好?

近期BRC-20大火&#xff0c;主打价值存储的比特币竟然生态比以太坊还热&#xff0c;但要论生态&#xff0c;以太坊才是真正的王者&#xff0c;因为其正在悄悄酝酿下一个重大升级——坎昆&#xff08;Dencun&#xff09;升级。 最新消息&#xff0c;以太坊开发者已经就Dencun升级…

【MySQL高级篇笔记-数据库的设计规范(中) 】

此笔记为尚硅谷MySQL高级篇部分内容 目录 一、为什么要数据库设计 二、范式 1、范式简介 2、范式都包括哪些 3、键和相关属性的概念 4、第一范式(1st NF) 5、第二范式(2nd NF) 6、第三范式(3rd NF) 7、小结 三、反范式化 1、概述 2、 应用举例 3、反范式的新问…