Android4.4电源管理——电源锁
//创建电源锁
![](https://code.csdn.net/assets/CODE_ico.png)
PowerManagerService.java
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
private SuspendBlocker createSuspendBlockerLocked(String name) {
SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
mSuspendBlockers.add(suspendBlocker);
return suspendBlocker;
}
//电源锁操作类的实现
![](https://code.csdn.net/assets/CODE_ico.png)
private final class SuspendBlockerImpl implements SuspendBlocker {
private final String mName;
private int mReferenceCount;
public SuspendBlockerImpl(String name) {
mName = name;
}
@Override
public void acquire() {
synchronized (this) {
mReferenceCount += 1;
if (mReferenceCount == 1) {
if (DEBUG_SPEW) {
Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
}
nativeAcquireSuspendBlocker(mName);
}
}
}
@Override
public void release() {
synchronized (this) {
mReferenceCount -= 1;
if (mReferenceCount == 0) {
if (DEBUG_SPEW) {
Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
}
nativeReleaseSuspendBlocker(mName);
} else if (mReferenceCount < 0) {
Log.wtf(TAG, "Suspend blocker \"" + mName
+ "\" was released without being acquired!", new Throwable());
mReferenceCount = 0;
}
}
}
}
//JNI层函数实现电源锁的获取
![](https://code.csdn.net/assets/CODE_ico.png)
com_android_server_power_PowerManagerService.cpp
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
//将电源锁写入到相应的文件中,相当于获得了电源锁
power.c
![](https://code.csdn.net/assets/CODE_ico.png)
int acquire_wake_lock(int lock, const char* id)
{
initialize_fds();
if (g_error) return g_error;
int fd;
if (lock == PARTIAL_WAKE_LOCK) {
fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
}
else {
return EINVAL;
}
return write(fd, id, strlen(id));
}
//打开记录电源锁的文件
![](https://code.csdn.net/assets/CODE_ico.png)
static inline void
initialize_fds(void)
{
if (g_initialized == 0) {
if(open_file_descriptors(NEW_PATHS) < 0)
open_file_descriptors(OLD_PATHS);
g_initialized = 1;
}
}
//记录电源锁的文件路径
![](https://code.csdn.net/assets/CODE_ico.png)
const char * const OLD_PATHS[] = {
"/sys/android_power/acquire_partial_wake_lock",
"/sys/android_power/release_wake_lock",
};
const char * const NEW_PATHS[] = {
"/sys/power/wake_lock",
"/sys/power/wake_unlock",
};
到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的android的上面几层Framework层、JNI层、HAL层都已经介绍了。下面就应该是和kernel层进行交互了。
但是在android/hardware/libhardware_legacy/power/power.c中的acquire_wake_lock()函数似乎没法和kernel层进行通信啊?最后的返回语句return write(fd, id, strlen(id))是一个系统调用,这里就实现了与kernel的交互。
kernel/power/main.c中的power_attr宏很多地方用到:
![](https://code.csdn.net/assets/CODE_ico.png)
- #define power_attr(_name) \
- static struct kobj_attribute _name##_attr = { \
- .attr = { \
- .name = __stringify(_name), \
- .mode = 0644, \
- }, \
- .show = _name##_show, \
- .store = _name##_store, \
- }
![](https://code.csdn.net/assets/CODE_ico.png)
- #ifdef CONFIG_USER_WAKELOCK
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
default y
User-space wake lock api. Write "lockname" or "lockname timeout"
to /sys/power/wake_lock lock and if needed create a wake lock.
Write "lockname" to /sys/power/wake_unlock to unlock a user wake
lock.
![](https://code.csdn.net/assets/CODE_ico.png)
- #ifdef CONFIG_PM_WAKELOCKS
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
default n
Allow user space to create, activate and deactivate wakeup source
objects with the help of a sysfs-based interface.
宏展开,等价于:
![](https://code.csdn.net/assets/CODE_ico.png)
- static struct kobj_attribute wake_lock_attr = {
- .attr = {
- .name = “wake_lock”,
- .mode = 0644,
- },
- .show = wake_lock_show,
- .store = wake_lock_store,
- }
![](https://code.csdn.net/assets/CODE_ico.png)
- static struct kobj_attribute wake_unlock_attr = {
- .attr = {
- .name = “wake_unlock”,
- .mode = 0644,
- },
- .show = wake_unlock_show,
- .store = wake_unlock_store,
- }
show和store函数的源码位于kernel/power/userwakelock.c。
![](https://code.csdn.net/assets/CODE_ico.png)
- static struct attribute * g[] = {
- &state_attr.attr,
- #ifdef CONFIG_PM_TRACE
- &pm_trace_attr.attr,
- &pm_trace_dev_match_attr.attr,
- #endif
- #ifdef CONFIG_PM_SLEEP
- &pm_async_attr.attr,
- &wakeup_count_attr.attr,
- #ifdef CONFIG_USER_WAKELOCK
- &wake_lock_attr.attr,
- &wake_unlock_attr.attr,
- #endif
- #ifdef CONFIG_PM_AUTOSLEEP
- &autosleep_attr.attr,
- #endif
- #ifdef CONFIG_PM_WAKELOCKS
- &wake_lock_attr.attr,
- &wake_unlock_attr.attr,
- #endif
- #ifdef CONFIG_PM_DEBUG
- &pm_test_attr.attr,
- #endif
- #ifdef CONFIG_PM_SLEEP_DEBUG
- &pm_print_times_attr.attr,
- #endif
- #endif
- #ifdef CONFIG_FREEZER
- &pm_freeze_timeout_attr.attr,
- #endif
- NULL,
- };
![](https://code.csdn.net/assets/CODE_ico.png)
- static struct attribute_group attr_group = {
- .attrs = g,
- };
pm_init()->
error = sysfs_create_group(power_kobj, &attr_group);
好了,我们该回到原来我们产生疑问的地方了这时我们还得关注其中的另一个函数acquire_wake_lock()->initialize_fds()。
![](https://code.csdn.net/assets/CODE_ico.png)
- initialize_fds(void)
- {
- // XXX: should be this:
- //pthread_once(&g_initialized, open_file_descriptors);
- // XXX: not this:
- if (g_initialized == 0) {
- if(open_file_descriptors(NEW_PATHS) < 0)
- open_file_descriptors(OLD_PATHS);
- g_initialized = 1;
- }
- }
其实这个函数中最核心的步骤就是open_file_descriptors(NEW_PATHS),顺序打开NEW_PATHS[ ]中的文件:
![](https://code.csdn.net/assets/CODE_ico.png)
- static int
- open_file_descriptors(const char * const paths[])
- {
- int i;
- for (i=0; i<OUR_FD_COUNT; i++) {
- int fd = open(paths[i], O_RDWR);
- if (fd < 0) {
- fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
- g_error = errno;
- return -1;
- }
- g_fds[i] = fd;
- }
- g_error = 0;
- return 0;
- }
- const char * const NEW_PATHS[] = {
- "/sys/power/wake_lock",
- "/sys/power/wake_unlock",
- };
总之经过着一系列的步骤后,最终我们将在 return write(fd, id, strlen(id));时调用android/kernel/kernel/power/userwakelock.c 中的 wake_lock_store()函数。
- ssize_t wake_lock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- long timeout;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 1, &timeout);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto bad_name;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
- if (timeout)
- wake_lock_timeout(&l->wake_lock, timeout);
- else
- wake_lock(&l->wake_lock);
- bad_name:
- mutex_unlock(&tree_lock);
- return n;
- }
- struct rb_root user_wake_locks;
- static struct user_wake_lock *lookup_wake_lock_name(
- const char *buf, int allocate, long *timeoutptr)
- {
- struct rb_node **p = &user_wake_locks.rb_node;
- struct rb_node *parent = NULL;
- struct user_wake_lock *l;
- int diff;
- u64 timeout;
- int name_len;
- const char *arg;
- /* Find length of lock name and start of optional timeout string */
- arg = buf;
- while (*arg && !isspace(*arg))
- arg++;
- //lock name的长度
- name_len = arg - buf;
- if (!name_len)
- goto bad_arg;
- while (isspace(*arg))
- arg++;
- /* Process timeout string */
- if (timeoutptr && *arg) {
- //(char **)&arg存储的是解析string的结束字符
- timeout = simple_strtoull(arg, (char **)&arg, 0);
- while (isspace(*arg))
- arg++;
- //如果解析string的结束字符不是’\0’
- if (*arg)
- goto bad_arg;
- /* convert timeout from nanoseconds to jiffies > 0 */
- timeout += (NSEC_PER_SEC / HZ) - 1;
- //do_div(a,b)的返回值是余数,商保存到a中
- do_div(timeout, (NSEC_PER_SEC / HZ));
- if (timeout <= 0)
- timeout = 1;
- *timeoutptr = timeout;
- } else if (*arg)
- //timeoutptr为NULL
- goto bad_arg;
- else if (timeoutptr)
- //*arg为0,没有timeout
- *timeoutptr = 0;
- /* Lookup wake lock in rbtree */
- //对于一颗空的红黑树,略过while。wake lock按照name从小到大的顺序存储到user_wake_locks红黑树中
- while (*p) {
- parent = *p;
- l = rb_entry(parent, struct user_wake_lock, node);
- diff = strncmp(buf, l->name, name_len);
- //如果buf是l->name的子串,那么l->name[name_len]就不会为0,但是buf[name_len]会为0
- if (!diff && l->name[name_len])
- diff = -1;
- if (debug_mask & DEBUG_ERROR)
- pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",
- name_len, buf, l->name, diff);
- if (diff < 0)
- p = &(*p)->rb_left;
- else if (diff > 0)
- p = &(*p)->rb_right;
- else
- return l;
- }
- /* Allocate and add new wakelock to rbtree */
- //allocate为0,表示不需要分配新的wakelock,只在rbtree上查找,找不到就出错了
- if (!allocate) {
- if (debug_mask & DEBUG_ERROR)
- pr_info("lookup_wake_lock_name: %.*s not found\n",
- name_len, buf);
- return ERR_PTR(-EINVAL);
- }
- l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);
- if (l == NULL) {
- if (debug_mask & DEBUG_FAILURE)
- pr_err("lookup_wake_lock_name: failed to allocate "
- "memory for %.*s\n", name_len, buf);
- return ERR_PTR(-ENOMEM);
- }
- memcpy(l->name, buf, name_len);
- if (debug_mask & DEBUG_NEW)
- pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);
- wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);
- //插入结点,并染成红色
- rb_link_node(&l->node, parent, p);
- rb_insert_color(&l->node, &user_wake_locks);
- return l;
- bad_arg:
- if (debug_mask & DEBUG_ERROR)
- pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",
- name_len, buf, arg);
- return ERR_PTR(-EINVAL);
- }
wake_lock_store()执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。
- static void wake_lock_internal(
- struct wake_lock *lock, long timeout, int has_timeout)
- {
- int type;
- unsigned long irqflags;
- long expire_in;
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- //检查type是否合法
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- //检查是否初始化过
- BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
- #ifdef CONFIG_WAKELOCK_STAT
- if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
- if (debug_mask & DEBUG_WAKEUP)
- pr_info("wakeup wake lock: %s\n", lock->name);
- wait_for_wakeup = 0;
- lock->stat.wakeup_count++;
- }
- if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
- (long)(lock->expires - jiffies) <= 0) {
- wake_unlock_stat_locked(lock, 0);
- lock->stat.last_time = ktime_get();
- }
- #endif
- if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
- lock->flags |= WAKE_LOCK_ACTIVE;
- #ifdef CONFIG_WAKELOCK_STAT
- lock->stat.last_time = ktime_get();
- #endif
- }
- //从inactive_locks上删除
- list_del(&lock->link);
- if (has_timeout) {
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
- lock->name, type, timeout / HZ,
- (timeout % HZ) * MSEC_PER_SEC / HZ);
- lock->expires = jiffies + timeout;
- lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
- list_add_tail(&lock->link, &active_wake_locks[type]);
- } else {
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d\n", lock->name, type);
- lock->expires = LONG_MAX;
- lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
- list_add(&lock->link, &active_wake_locks[type]);
- }
- if (type == WAKE_LOCK_SUSPEND) {
- current_event_num++;
- #ifdef CONFIG_WAKELOCK_STAT
- if (lock == &main_wake_lock)
- update_sleep_wait_stats_locked(1);
- else if (!wake_lock_active(&main_wake_lock))
- update_sleep_wait_stats_locked(0);
- #endif
- if (has_timeout)
- expire_in = has_wake_lock_locked(type);
- else
- expire_in = -1;
- if (expire_in > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, start expire timer, "
- "%ld\n", lock->name, expire_in);
- mod_timer(&expire_timer, jiffies + expire_in);
- } else {
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, stop expire timer\n",
- lock->name);
- if (expire_in == 0)
- queue_work(suspend_work_queue, &suspend_work);
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
//电源锁的使用
![](https://code.csdn.net/assets/CODE_ico.png)
/**
* Updates the suspend blocker that keeps the CPU alive.
*
* This function must have no other side-effects.
*/
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
}
// Then release suspend blockers if needed.
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
}
//判断是否处于亮屏或者正在变化阶段
![](https://code.csdn.net/assets/CODE_ico.png)
private boolean needDisplaySuspendBlocker() {
//正处于变化阶段
if (!mDisplayReady) {
return true;
}
if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
//有疑问?
// If we asked for the screen to be on but it is off due to the proximity
// sensor then we may suspend but only if the configuration allows it.
// On some hardware it may not be safe to suspend because the proximity
// sensor may not be correctly configured as a wake-up source.
if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
|| !mSuspendWhenScreenOffDueToProximityConfig) {
return true;
}
}
return false;
}
Android4.4电源管理——电源锁相关推荐
- iTOP-4418开发板支持动态调频,AXP228电源管理,预留锂电池接口,内置充放电电路及电量计...
iTOP-4418开发板 支持动态调频,AXP228电源管理,预留锂电池接口,内置充放电电路及电量计 核心板320PIN全引出,16G存储高配版本,核心板4418/6818全兼容,并跨行业大量应用 系 ...
- Android电源管理介绍
一.电源管理基础知识 1.1电源管理的几种状态 Android kernel源码中,定义了三种电源状态,在kernel/power/suspend.c中: 对应的宏定义/include/linux/s ...
- linux pcie热插拔驱动_Linux安装TLP-高级电源管理工具
唉,最近有了一个新问题.系统版本Ubuntu 18.04,笔记本,一旦断开电源,电脑就会卡住.试过的方法: 更新了固件 sudo apt update sudo apt upgrade -y 管了几天 ...
- 时钟,复位和电源管理
文章目录 一.电源管理和复位 二.时钟 1.时钟的分类和特性 2.时钟图 杨桃32学习笔记,本文图片文字皆为转述 一.电源管理和复位 (1)8MHZ的振荡器给arm内核提供,40khz给RTC使用也就 ...
- 关闭linux服务器电源,linux关闭ACPI电源管理模块
一.运行环境 # cat /etc/redhat-release CentOS release 6.2 (Final) # uname -a Linux web-server- 2.6.-.el6.x ...
- Freescale 基于IMX536处理器的Dialog DA9053电源管理参考设计
Freescale 基于IMX536处理器的Dialog DA9053电源管理参考设计 ----------墨翟科技(上海)有限公司编撰 在2012年飞思卡尔技术论坛中国站的展示区,Dialog公司推 ...
- android电源驱动程序,[转]Android虚拟电源管理驱动
Android系统如果没有电源管理相关的驱动程序,在启动时将会提示如下错误: I/SystemServer( 50): Starting Battery Service. E/BatterySer ...
- IC基础知识(4)电源管理简介:稳压器IC
文章目录 写在前面 正文 线性与开关 线性稳压器 开关稳压器 其他类型的功率IC 结论 写在前面 原文链接:Introduction to Power Management: Voltage Regu ...
- FPGA内部电源管理详解
做了这么长时间的FPGA的设计,也看了很多这方面的书籍资料,不管是编程还是调试,一直都只在关心有没有实现功能,没有去深入理解FFPGA的内部结构,接下来这几篇文章将着重分析FPGA设计的各个部分细节. ...
最新文章
- 计算机领域收费sci期刊,计算机领域收费sci期刊 - 百度学术
- python中any的妙用
- Leetcode python《热题 HOT 100》1. 两数之和
- c语言黄建灯第七章答案,c语言实训大纲.doc
- NSArray	数组
- 关于Redis在windows上运行及fork函数问题
- Mbps和MB/s之间的换算
- 携程旅行网的盈利模式
- 运用设计模式实现Sql语句动态转换
- android平台获取手机IMSI,IMEI ,序列号,和 手机号的方法
- oracle 18c 转 11g,安装Oracle:Oracle 18c、Oracle 11g
- COM笔记-Widows 注册表
- 事业单位采购计算机的申请报告,事业单位采购申请报告
- 一款简单的本地音乐播放器,界面美观、包括主题切换、歌单管理等等
- 超声波测距仪编程_Arduino轻松学Mixly编程第9课 超声波测距仪
- 排名:百度小程序 微信 + 支付宝 + 百度 + 头条 商城源码-拓客营销
- 全球投资移民青睐低气候风险地,最具气候韧性国家排名前五都在北半球 | 美通社头条...
- 服务器显示屏出现白屏,前端性能优化之白屏时间
- 列出美国每个州及一个邮编
- Ubuntu16.04+GTX1060mq(驱动版本430.64)安装CUDA10.0