Android 电源管理分析

一 简述

手机不同于PC,手机使用的是可移动电源,由于电源的电量有限,因此如何做到既让“马儿跑又要马儿不吃草”,电源管理系统尤为重要。
本文主要从上层应用入手,介绍安卓系统如何进行电源系统的管理和优化,提高手机的待机能力。
先看一下手机的几个耗电大户,分别是:
1)显示屏
2)AP的cpu和modem的cpu
3)其他的硬件外设
所以,电源优化一般是根据上述几个耗电环节进行优化。
1)显示屏一般技术有:自动熄屏、自动亮度调节、黑白显示等
2)CPU占用上 多核系统的hotplug、动态调频DVFS、PELT或者EAS调度策略、进程冻结技术等,在无交互时cpu自动休眠等
3)硬件外设 在SOC的设计中,可能为每个外设单元设置单独的电源子系统,在空闲状态时,可以自动休眠,设备不运行节省电源的消耗。

二 应用开发中牵扯到的电源管理部分

1) 使屏幕保持开启状态
在Activity 中使用 FLAG_KEEP_SCREEN_ON

    public class MainActivity extends Activity {
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
      }
    }
    

在应用的布局 XML 文件中,使用 android:keepScreenOn 属性:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:keepScreenOn="true">
        ...
    </RelativeLayout>

2) CPU占用
如果需要使 CPU 保持运行状态,需要 WAKE_LOCK来保持CPU一直处于唤醒状态

<uses-permission android:name="android.permission.WAKE_LOCK" />

持有wakeLock可以避免CPU进入休眠状态

    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
            "MyApp::MyWakelockTag");
    wakeLock.acquire();
  1. 使用可使设备保持唤醒状态的广播接收器
    WakefulBroadcastReceiver 是一种特殊类型的广播接收器,可以为应用或者service保持WAKE_LOCK,使用方法如下:
<receiver android:name=".MyWakefulReceiver"></receiver>

最后用completeWakefulIntent(intent);完成WAKE_LOCK的释放

public class MyWakefulReceiver extends WakefulBroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

            // Start the service, keeping the device awake while the service is
            // launching. This is the Intent to deliver to the service.
            Intent service = new Intent(context, MyIntentService.class);
            startWakefulService(context, service);
        }
    }
  public class MyIntentService extends IntentService {
        public static final int NOTIFICATION_ID = 1;
        private NotificationManager notificationManager;
        NotificationCompat.Builder builder;
        public MyIntentService() {
            super("MyIntentService");
        }
        @Override
        protected void onHandleIntent(Intent intent) {
            Bundle extras = intent.getExtras();
            // Do the work that requires your app to keep the CPU running.
            // ...
            // Release the wake lock provided by the WakefulBroadcastReceiver.
            MyWakefulReceiver.completeWakefulIntent(intent);
        }
    }

三 PM在FW部分

在frameworks/base/services/core/java/com/android/server/power/目录下,PowerManagerService.java和ThermalManagerService.java
PMS主要调用底层HAL的两处

hardware/interfaces/power/ 
system/hardware/interfaces/suspend/

hardware/interfaces/power/ 主要是power总的控制开关,可以从相关aidl文件可以看出

 interface IPower {

oneway void setMode(in Mode type, in boolean enabled);
 boolean isModeSupported(in Mode type);
oneway void setBoost(in Boost type, in int durationMs);
boolean isBoostSupported(in Boost type);

}

而system/hardware/interfaces/suspend/主要来控制“挂起”相关,以及提供WAKE_LOCK相关控制,其HAL层主要是通过与内核文件的交互来完成相关控制

/sys/power/wake_lock
/sys/power/wake_unlock
/sys/power/wakeup_count
/sys/power/state

主要通过往/sys/power/state写"mem"后系统进入休眠

四 PM内核部分

Android的电源管理系统主要实现在内核的如下目录

kernel/power
drivers/base/power
arch/xxx/mach-xxx/

在我们往/sys/power/state写mem时进入如下函数

kernel/power/main.c
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
               const char *buf, size_t n)
{
    suspend_state_t state;
    int error;

    error = pm_autosleep_lock();
    if (error)
        return error;

    if (pm_autosleep_state() > PM_SUSPEND_ON) {
        error = -EBUSY;
        goto out;
    }

    state = decode_state(buf, n);
    if (state < PM_SUSPEND_MAX) {
        if (state == PM_SUSPEND_MEM)
            state = mem_sleep_current;

        error = pm_suspend(state);
    } else if (state == PM_SUSPEND_MAX) {
        error = hibernate();
    } else {
        error = -EINVAL;
    }

 out:
    pm_autosleep_unlock();
    return error ? error : n;
}

power_attr(state);

通过调用pm_suspend进入suspend state并挂起系统
系统还可以自动挂起,主要实现在kernel/power/autosleep.c中,如果系统不能自动挂起的话,多半是wake_lock没有空导致

static void try_to_suspend(struct work_struct *work)
{
    unsigned int initial_count, final_count;

    if (!pm_get_wakeup_count(&initial_count, true))
        goto out;

    mutex_lock(&autosleep_lock);

    if (!pm_save_wakeup_count(initial_count) ||
        system_state != SYSTEM_RUNNING) {
        mutex_unlock(&autosleep_lock);
        goto out;
    }

    if (autosleep_state == PM_SUSPEND_ON) {
        mutex_unlock(&autosleep_lock);
        return;
    }
    if (autosleep_state >= PM_SUSPEND_MAX)
        hibernate();
    else
        pm_suspend(autosleep_state);

    mutex_unlock(&autosleep_lock);

    if (!pm_get_wakeup_count(&final_count, false))
        goto out;

    /*
     * If the wakeup occured for an unknown reason, wait to prevent the
     * system from trying to suspend and waking up in a tight loop.
     */
    if (final_count == initial_count)
        schedule_timeout_uninterruptible(HZ / 2);

 out:
    queue_up_suspend_work();
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342