android 2.3 电量管理

2024-04-16 07:58
文章标签 android 管理 2.3 电量

本文主要是介绍android 2.3 电量管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.     介绍.... 4

2.     电池管理.... 4

2.1.      FrameWork.. 5

2.1.1.       监听... 5

2.1.1.1.     UEventObserver的实现... 6

2.1.1.2.     uevent 8

2.1.2.       状态读取... 9

2.1.3.       更新显示... 9

2.2.      驱动... 11

3.     用电统计.... 20


1.       介绍

              首先区分一下电源管理, 电池管理和用电统计三个概念。

l         电源管理:前一篇文章讲的是电源管理, 电源管理的目的是节电, 让设备在空闲的时间进入睡眠状态。

l         电池管理: 电池管理的目的是对电池电量和状态的管理, 比如电量变化时和进入充电状态时更新任务栏上的进度条, 当系统低电量时通知用户, 电量低到一定程度时自动关机等。

l         用电统计:用电统计的目的则是统计系统中一些模块, 服务和应用程序的耗电情况, 并反馈给用户。

       这篇文章是关于电池管理和用电统计的。

2.       电池管理

       Android电池管理的功能其实很简单:

l         监测电池电量的变化并更新显示界面

l         监听进入充电状态和退出充电状态消息并更新界面

2.1.      FrameWork

       



2.1.1.          监听

       在BatteryService定义了UEventObserver, uevent是Linux内核用来向用户空间主动上报事件的机制,关于uevent请参见2.1.1.2节, JAVA中的UEventObserver就用来监听uevent的。

private UEventObserver mUEventObserver = new UEventObserver() {

        @Override

        public void onUEvent(UEventObserver.UEvent event) {

            update();

        }

};

然后调用mUEventObserver.startObserving("SUBSYSTEM=power_supply")只监听属性SUBSYSTEM 为“power_supply”的消息。 也就是说当系统进入充电状态和退出充电状态时, 电量变化时就会调用到这个onUEvent函数来处理变化。

2.1.1.1.    UEventObserver的实现

      UEventObserver的实现分为三层,

UEventObserver.java->android_os_UEventObserver.cpp->hardware\libhardware_legacy\uevent\uevent.c

l         API层是com.android.os.UEventObserver

l         JNI层是android_os_UEventObserver.cpp, 很浅

l         Hal层是hardware\libhardware_legacy\uevent\uevent.c, 直接和内核通信

 

       当第一次调用mUEventObserver.startObserving会启动一个UEventThread, next_event会返回监听到的uevent事件, 然后再判断是不是我们所关心的, 如果是就会回调我们注册的onUEvent函数。如下:

private static class UEventThread extends Thread {

        public void run() {

            native_setup();

 

            byte[] buffer = new byte[1024];

            int len;

            while (true) {

                len = next_event(buffer);

                if (len > 0) {

                    String bufferStr = new String(buffer, 0, len);  // easier to search a String

                    synchronized (mObservers) {

                        for (int i = 0; i < mObservers.size(); i += 2) {

                            if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {

                                ((UEventObserver)mObservers.get(i+1))

                                        .onUEvent(new UEvent(bufferStr));

                            }

                        }

                    }

                }

            }

        }

       native_setup()是jni 如下:

static void

android_os_UEventObserver_native_setup(JNIEnv *env, jclass clazz)

{

    if (!uevent_init()) {

        jniThrowException(env, "java/lang/RuntimeException",

                          "Unable to open socket for UEventObserver");

    }

}

    uevent_init()是hal,创建用于监听内核uevent事件的socket, 如下:

 

int uevent_init()

{

    struct sockaddr_nl addr;

    int sz = 64*1024;

    int s;

 

    memset(&addr, 0, sizeof(addr));

    addr.nl_family = AF_NETLINK;

    addr.nl_pid = getpid();

    addr.nl_groups = 0xffffffff;

 

    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);

    if(s < 0)

        return 0;

 

    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));

 

    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {

        close(s);

        return 0;

    }

 

    fd = s;

    return (fd > 0);

}

 

     next_event是jni,如下:

static int

android_os_UEventObserver_next_event(JNIEnv *env, jclass clazz, jbyteArray jbuffer)

{

    int buf_sz = env->GetArrayLength(jbuffer);

    char *buffer = (char*)env->GetByteArrayElements(jbuffer, NULL);

    int length = uevent_next_event(buffer, buf_sz - 1);

    env->ReleaseByteArrayElements(jbuffer, (jbyte*)buffer, 0);

    return length;

}

    uevent_next_event是hal, 等待uevent事件, 如下:

int uevent_next_event(char* buffer, int buffer_length)

{

    while (1) {

        struct pollfd fds;

        int nr;

   

        fds.fd = fd;

        fds.events = POLLIN;

        fds.revents = 0;

        nr = poll(&fds, 1, -1);

    

        if(nr > 0 && fds.revents == POLLIN) {

            int count = recv(fd, buffer, buffer_length, 0);

            if (count > 0) {

                return count;

            }

        }

    }

   

    // won't get here

    return 0;

}

       至于netlink socket的原理不做过多解释, 我们现在更关心的是我们的电池驱动如何发送出uevent。

2.1.1.2.    uevent

          关于linux设备模型请参考《LDD3》的第14章。

          如果对节点的动态动态创建过程有了解的话, 那么对uevent一定不会陌生。 当发现设备调用device_add函数时, device_add便会调用kobject_uevent函数发出一个uevent。 应用层的udev(当然android是没有udev的, 动态节点创建时由init进程做的)就会监听这个uevent来创建设备节点。 当然当设备移除时也会调用device_remove也会发出一个uevent,udev收到这个消息就删除设备节点。

          每个uevent都包含一些属性, 所有uevent都有如下属性, 下面只列出几个重要的:

l         ACTION: add, remove或change等。

l         SUBSYSTEM:“devices”,“input”,“power_supply”等。

l         DEVPATH:发出uevent的kobject的sys对应路径。

          当然不同的子系统中发出的uevent又会可能有相应的属性发出, 还记得每个kset对应一个子系统吧, 比如/sys/devices, /sys/block, /sys/class/input, /sys/class/power_supply, 当添加一个kset时会为这个kset注册一个kset_uevent_ops。 当一个kobject发出一个uevent时, 就会去寻找这个kobject所属的kset, 然后调用这个kset里面的kset_uevent_ops来添加子系统相关的一些属性。比如power_supply子系统里面发出的uevent都会有POWER_SUPPLY_NAME这个属性, 值可以是“ac”, “usb”或者“battery”。

          当然驱动也是可以为uevent添加属性的, 调用kobject_uevent_env函数发uevent即可,kobject_uevent_env声明如下:

       int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[])

       发出去uevent, 应用层就可以通过netlink socket的方式来接收。

2.1.2.          状态读取

       update()函数里会调用nativeUpdate()通过进入c++层, nativeUpdate在com_android_server_BatteryService.cpp中。 Android的Linux 内核中的电池驱动会提供如下sysfs接口给

FrameWork:

/sys/class/power_supply/ac/online
/sys/class/power_supply/ac/type
 
/sys/class/power_supply/usb/online
/sys/class/power_supply/usb/type
 
/sys/class/power_supply/battery/status
/sys/class/power_supply/battery/health
/sys/class/power_supply/battery/present
/sys/class/power_supply/battery/capacity
/sys/class/power_supply/battery/batt_vol
/sys/class/power_supply/battery/batt_temp
/sys/class/power_supply/battery/technology
/sys/class/power_supply/battery/type

 

       当监听到power_supply变化的消息后, nativeUpdate函数就会重新读取以上sysfs文件获得当前状态。这里应该注意的是读到的capacity为0-100之间的数值, 100代表满电。

2.1.3.          更新显示

       当发现有变化时就会发出BroadCast, 关心电池变化事件的模块就会定义BroadCastReceiver来响应, 比如状态栏。有如下intent会在相应情况下通过BroadCast发出:

l         Intent.ACTION_BATTERY_CHANGED:不仅是电量变换, 包括connected和disconnected等所有变化, 都会发出这个broadcast。

l         Intent.ACTION_POWER_CONNECTED

l         Intent.ACTION_POWER_DISCONNECTED

l         Intent.ACTION_BATTERY_LOW

l         Intent.ACTION_BATTERY_OKAY

 

       通过在Eclipse中进行search, 找到关心Intent.ACTION_BATTERY_CHANGED的地方有:

l         NotificationManagerService:更新电源灯的更亮度和让通知灯闪几下。

l         PowerManagerService: 代码如下

    private final class BatteryReceiver extends BroadcastReceiver {

        @Override

        public void onReceive(Context context, Intent intent) {

            synchronized (mLocks) {

                boolean wasPowered = mIsPowered;

                mIsPowered = mBatteryService.isPowered();

 

                if (mIsPowered != wasPowered) {

                    // update mStayOnWhilePluggedIn wake lock

                    updateWakeLockLocked();

 

                    // treat plugging and unplugging the devices as a user activity.

                    // users find it disconcerting when they unplug the device

                    // and it shuts off right away.

                    // to avoid turning on the screen when unplugging, we only trigger

                    // user activity when screen was already on.

                    // temporarily set mUserActivityAllowed to true so this will work

                    // even when the keyguard is on.

                    synchronized (mLocks) {

                        if (!wasPowered || (mPowerState & SCREEN_ON_BIT) != 0) {

                            forceUserActivityLocked();

                        }

                    }

                }

            }

        }

    }

l         UiModeManagerService: 会申请一个FULL_WAKE_LOCK, keep screen on when charging and in car mode。

l         WifiService:注释如下

  

l         com.android.server.Connectivity.Tethering: 代码如下,还不清楚什么用。

if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {

    mUsbConnected = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)

                        == BatteryManager.BATTERY_PLUGGED_USB);

    Tethering.this.updateUsbStatus();

}

l         packages.SystemUI.src.com.android.systemui.statusbar: 更新状态栏电池量的显示。

l         KeyguardUpdateMonitor:代码如下, 还不清楚作用。

private void handleBatteryUpdate(int pluggedInStatus,int batteryLevel) {

        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");

        final boolean pluggedIn = isPluggedIn(pluggedInStatus);

        if (isBatteryUpdateInteresting(pluggedIn, batteryLevel)) {

            mBatteryLevel = batteryLevel;

            mDevicePluggedIn = pluggedIn;

            for (int i = 0; i < mInfoCallbacks.size(); i++) {

                mInfoCallbacks.get(i).onRefreshBatteryInfo(

                        shouldShowBatteryInfo(), pluggedIn, batteryLevel);

            }

       }

}

 

关心Intent.ACTION_POWER_CONNECTED的地方有:

l         packages.SystemUI.src.com.android.systemui.statusbar: 更新状态栏电池量的显示。

 

关心Intent.ACTION_POWER_DISCONNECTED的地方有:

 

关心Intent.ACTION_BATTERY_LOW的地方有:

l         packages.SystemUI.src.com.android.systemui.statusbar: 更新状态栏电池量的显示, 弹出dialog并发出声音提示用户低电量。

 

关心Intent.ACTION_BATTERY_OKAY的地方有:

l         packages.SystemUI.src.com.android.systemui.statusbar: 更新状态栏电池量的显示。

2.2 驱动

关于驱动实现遵循linux kernel power-supply子系统规范即可, 可参考示例代码较多。

              

3.       用电统计

       

       上图是显示Android系统用电统计结果的界面, 这个界面在Settings->About Phone->Battery use里。

用电统计是对Android电源管理系统缺点的弥补, Android电源管理系统的缺点是只有所有程序设计良好电源管理系统才能工作的出色, 一坏就会坏一锅粥。 当你发现你的系统莫名其妙很快没电了时, 你就会可以通过用电统计找到原因, 以便禁掉某些功能或卸载某些程序。

       com.android.server.BatteryStatsService负责统计, 其它模块比如WakeLock和PowerManagerService会向BatteryStatsService喂数据。BatteryStatsService在ActivityManagerService中创建, 如下所示:

mBatteryStatsService = new BatteryStatsService(new File(systemDir, "batterystats.bin").toString());

可见统计的数据保存在batterystats.bin里面。

Settings程序也是通过BatteryStatsService获得统计数据, 然后把统计数据传入BatteryStatsImpl来分析。

这部分细节比较复杂就先点到为止, 看以后是不是有深入的需要。

 

4.       实际问题

当由充电状态转到电池供电时,读到电池电压会有0。2v左右跳降。 当由电池供电转到充电状态时,读到电池电压会有0。2v左右跳升。这就需要驱动或hal层维护两张电压电量对应表。


这篇关于android 2.3 电量管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/908215

相关文章

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使