一 简述

手机不同于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 属性:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:keepScreenOn="true">

...

2) CPU占用

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

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

PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);

WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,

"MyApp::MyWakelockTag");

wakeLock.acquire();

使用可使设备保持唤醒状态的广播接收器

WakefulBroadcastReceiver 是一种特殊类型的广播接收器,可以为应用或者service保持WAKE_LOCK,使用方法如下:

最后用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();

}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐