




已阅读5页,还剩68页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
android 和linux的休眠唤醒机制 四、android层源码解析1.hardware/libhardware_legacy/power/power.c /HAI层2. frameworks/base/core/jni/android_os_Power.cpp /jni层3frameworks/base/core/java/android/os/Power.java /java层在linux之上经过android的软件堆层层封装,最终在上层的java应用程序中使用。休眠唤醒也是从最上层发出的命令,然后一层一层地将参数解析,往最底层传,最后走上标准linux的休眠唤醒之路。这一部分将会初略分析休眠唤醒机制上linux之上所走的路线。在linux之上,存在一个hal层,专门做和linux内核设备打交道的事情,这里也不例外。休眠唤醒机制的hal层源码位于:hardware/libhardware_legacy/power/power.c该文件源码比较简单,下面列举重点片段:enum ACQUIRE_PARTIAL_WAKE_LOCK = 0,RELEASE_WAKE_LOCK,REQUEST_STATE,OUR_FD_COUNT;const char * const NEW_PATHS = /sys/power/wake_lock,/sys/power/wake_unlock,/sys/power/state;static int g_initialized = 0;static int g_fdsOUR_FD_COUNT;static const char *off_state = mem;static const char *on_state = on;static int open_file_descriptors(const char * const paths)int i;for (i=0; iOUR_FD_COUNT; i+) int fd = open(pathsi, O_RDWR);if (fd 0) fprintf(stderr, fatal error opening %sn, pathsi);g_error = errno;return -1;g_fdsi = fd;g_error = 0;return 0;static inline void initialize_fds(void)if (g_initialized = 0) if(open_file_descriptors(NEW_PATHS) = 0;int set_screen_state(int on)QEMU_FALLBACK(set_screen_state(on);LOGI(* set_screen_state %d, on);initialize_fds();if (g_error) return g_error;char buf32;int len;if(on)len = sprintf(buf, on_state);elselen = sprintf(buf, off_state);len = write(g_fdsREQUEST_STATE, buf, len);if(len GetStringUTFChars(idObj, NULL);acquire_wake_lock(lock, id);env-ReleaseStringUTFChars(idObj, id);/ 对wakelock加锁函数static void releaseWakeLock(JNIEnv *env, jobject clazz, jstring idObj)if (idObj = NULL) throw_NullPointerException(env, id is null);return ;const char *id = env-GetStringUTFChars(idObj, NULL);release_wake_lock(id);env-ReleaseStringUTFChars(idObj, id);/ 对wakelock解锁函数static int setScreenState(JNIEnv *env, jobject clazz, jboolean on)return set_screen_state(on);/ 休眠唤醒的函数Jni的方法需要注册到上层才可以使用,同时也需要在上层的对应java类中声明了native才可以使用。那么这里的方法在java中对应的声明在哪里呢?frameworks/base/core/java/android/os/Power.java,该文件定义一个java类,如下:public class Power/ cant instantiate this classprivate Power()/* Wake lock that ensures that the CPU is running. The screen might* not be on.*/public static final int PARTIAL_WAKE_LOCK = 1;/* Wake lock that ensures that the screen is on.*/public static final int FULL_WAKE_LOCK = 2;public static native void acquireWakeLock(int lock, String id);public static native void releaseWakeLock(String id); /* Turn the screen on or off* param on Whether you want the screen on or off*/public static native int setScreenState(boolean on);声明的jni接口应该是被java server在使用,这里就是专门的电源管理服务:PowerManagerService使用,具体源码位置在:frameworks/base/services/java/com/android/server/PowerManagerService.java。android在最上层还提供了现场的android.os.PowerManager类(frameworks/base/core/java/android/os/PowerManager.java)来供app使用,PowerManager类会调用java服务PowerManagerService的方法来完成与wakelock相关的工作。 frameworks/base/core/java/android/os/PowerManager.java类PowerManager中内嵌了一个WakeLock类,另外还定义了wakelock的类型,下面是代码片段:public class PowerManagerprivate static final String TAG = PowerManager;/* Wake lock that ensures that the CPU is running. The screen might* not be on.*/public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG;/* Wake lock that ensures that the screen and keyboard are on at* full brightness.*/public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT | WAKE_BIT_KEYBOARD_BRIGHT;/* Wake lock that ensures that the screen is on at full brightness;* the keyboard backlight will be allowed to go off.*/public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;/* Wake lock that ensures that the screen is on (but may be dimmed);* the keyboard backlight will be allowed to go off.*/public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;/* Wake lock that turns the screen off when the proximity sensor activates.* Since not all devices have proximity sensors, use* link #getSupportedWakeLockFlags() getSupportedWakeLockFlags() to determine if* this wake lock mode is supported.* hide*/public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;public class WakeLockWakeLock(int flags, String tag)switch (flags & LOCK_MASK) case PARTIAL_WAKE_LOCK:case SCREEN_DIM_WAKE_LOCK:case SCREEN_BRIGHT_WAKE_LOCK:case FULL_WAKE_LOCK:case PROXIMITY_SCREEN_OFF_WAKE_LOCK:break;default:throw new IllegalArgumentException();mFlags = flags;mTag = tag;mToken = new Binder();public void acquire()synchronized (mToken) if (!mRefCounted | mCount+ = 0) try mService.acquireWakeLock(mFlags, mToken, mTag); catch (RemoteException e) mHeld = true;public void release(int flags)synchronized (mToken) if (!mRefCounted | -mCount = 0) try mService.releaseWakeLock(mToken, flags); catch (RemoteException e) mHeld = false;if (mCount 0) throw new RuntimeException(WakeLock under-locked + mTag);public WakeLock newWakeLock(int flags, String tag)if (tag = null) throw new NullPointerException(tag is null in PowerManager.newWakeLock);return new WakeLock(flags, tag);public void goToSleep(long time) try mService.goToSleep(time); catch (RemoteException e) public PowerManager(IPowerManager service, Handler handler)mService = service; 21:40 评论 / 浏览 (0 / 378)2011-05-29缩略显示Android在标准linux基础上对休眠唤醒的实现(二)LinuxAndroid活动工作三、kernel层源码解析 - wakelock的重要地位wakelock在android的休眠唤醒机制中扮演着及其重要的角色,主要源码位于文件:kernel/kernel/power/wakelock.c,kernel/include/linux/wakelock.h中。wakelocks_init()函数所做的工作是整个wakelock可以工作起来的基础,所有这里先说说这个函数。static int _init wakelocks_init(void)int ret;int i;for (i = 0; i flags & WAKE_LOCK_ACTIVE) lock-flags |= WAKE_LOCK_ACTIVE;/ wakelock状态为inactive,则更改为activeif (has_timeout) / wake_lock_timeout()会传入1if (wakelock_debug_mask & DEBUG_WAKE_LOCK)pr_info(wake_lock_internal: %s, type %d, timeout %ld.%03lun,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_lockstype); / acquire a non-timeout wakelock 添加一个非超时锁else / wake_lock ()会传入0if (wakelock_debug_mask & DEBUG_WAKE_LOCK)pr_info(wake_lock_internal: %s, type %dn, lock-name, type);lock-expires = LONG_MAX; / 设置成超时时间最大值lock-flags &= WAKE_LOCK_AUTO_EXPIRE; / 非超时锁标志list_add(&lock-link, &active_wake_lockstype);/ 将刚刚设置的非超时锁加到对应类型的活动锁链表中解锁的时候,这两种形式的锁所使用函数都是一样了:wake_unlock(),该函数中会首先作如下操作:lock-flags &= (WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);/ 清除锁活动标志和自动超时标志list_del(&lock-link); / 从锁对应的活动链表上摘除list_add(&lock-link, &inactive_locks); / 将unlock的锁挂接到非活动链表inactive_locks上前面已经说了只有类型为WAKE_LOCK_SUSPEND的wakelock被上锁才会阻止系统进入suspend,那么也就是说只要链表active_wake_locksWAKE_LOCK_SUSPEND为NULL,那么系统就可以执行suspend的流程了。Android对linux的改造,让其可以在三种情况下进入linux的标准suspend的流程:1. wake_unlock(),这个应该是最容易想到的,只要系统有对WAKE_LOCK_SUSPEND类型的wakelock解锁的动作,都有可能会进入suspend流程开始休眠,为什么是有可能呢?因为可能还有超时锁没有被超时解锁。下面看一下代码片段:void wake_unlock(struct wake_lock *lock)if (type = WAKE_LOCK_SUSPEND) / 貌似只在处理这个类型的wakelocklong has_lock = has_wake_lock_locked(type);/ 这个函数蛮重要,它来检查type类型的链表上是否还有锁被上锁了。/ 其返回值如果是0,说明没有该类型的锁被持有了;返回非0表明就是这个类型的活动链表上还存在超时锁但是没有非超时锁了,这个返回值就是当前时间距离最后超时的锁超时时间的jiffies值;如果返回-1,那表明还有该类型的非超时锁被持有。if (wakelock_debug_mask & DEBUG_WAKE_LOCK)pr_info(wake_unlock: has_lock = 0x%xn , has_lock); if (has_lock 0) if (wakelock_debug_mask & DEBUG_EXPIRE)pr_info(wake_unlock: %s, start expire timer, %ldn, lock-name, has_lock);mod_timer(&expire_timer, jiffies + has_lock);/ 修改定时器的超时值并add该定时器 else / 已经没有超时锁了if (del_timer(&expire_timer) / 删除定时器if (wakelock_debug_mask & DEBUG_EXPIRE)pr_info(wake_unlock: %s, stop expire timern, lock-name);if (has_lock = 0) / !=0,表明还有该类型的非超时锁被持有,现在还不能进入suspendpr_info(wake_unlock: (%s) suspend_work_queue suspend_workn , lock-name);queue_work(suspend_work_queue, &suspend_work);/ 提交suspend的工作项,开始执行标准linux的suspend流程 spin_unlock_irqrestore(&list_lock, irqflags);2. 超时锁超时之后,定时器的回调函数会执行会查看是否有其他的wakelock, 如果没有, 就在这里让系统进入睡眠。static void expire_wake_locks(unsigned long data)long has_lock;unsigned long irqflags;if (debug_mask & DEBUG_EXPIRE)pr_info(expire_wake_locks: startn);spin_lock_irqsave(&list_lock, irqflags);if (debug_mask & DEBUG_SUSPEND)print_active_locks(WAKE_LOCK_SUSPEND);has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);if (debug_mask & DEBUG_EXPIRE)pr_info(expire_wake_locks: done, has_lock %ldn, has_lock);if (has_lock = 0)/ 如果没有SUSPEND类型的wakelock处于active,那么将调用suspendqueue_work(suspend_work_queue, &suspend_work);spin_unlock_irqrestore(&list_lock, irqflags);static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);列出以下一个重要的函数源码:static long has_wake_lock_locked(int type)struct wake_lock *lock, *n;long max_timeout = 0;BUG_ON(type = WAKE_LOCK_TYPE_COUNT);list_for_each_entry_safe(lock, n, &active_wake_lockstype, link) if (lock-flags & WAKE_LOCK_AUTO_EXPIRE) long timeout = lock-expires - jiffies;if (timeout max_timeout)max_timeout = timeout; elsereturn -1;return max_timeout;3. 这个可能有人觉得匪夷所思,就是在wake_lock_ _timeout()函数中,调用了内部函数wake_lock_internal()。这里只有在对超时锁上锁的时候才有可能进入休眠,如果对一个费超时锁上锁的话,那么就没有必要去检查活动链表了。static void wake_lock_internal(struct wake_lock *lock, long timeout, int has_timeout)if (type = WAKE_LOCK_SUSPEND) current_event_num+;#ifdef CONFIG_WAKELOCK_STATif (lock = &main_wake_lock)update_sleep_wait_stats_locked(1);else if (!wake_lock_active(&main_wake_lock)update_sleep_wait_stats_locked(0);#endifif (has_timeout) / 超时锁的时候传进来的是1expire_in = has_wake_lock_locked(type);/ 检查当前锁类型链表上是否还有锁处于active的状态,无返回0elseexpire_in = -1; / 如果是非超时锁的话,这里直接赋值-1,省去了活动链表检查步骤了if (expire_in 0) if (debug_mask & DEBUG_EXPIRE)pr_info(wake_lock: %s, start expire timer, %ldn, lock-name, expire_in);/ modify the time wakelock is expiredmod_timer(&expire_timer, jiffies + expire_in); else if (del_timer(&expire_timer)if (debug_mask & DEBUG_EXPIRE) 21:33 评论 / 浏览 (0 / 860)2011-05-29缩略显示新版linux系统设备架构中关于电源管理方式的变更Linux数据结构新版linux系统设备架构中关于电源管理方式的变更based on linux-2.6.32一、设备模型各数据结构中电源管理的部分linux的设备模型通过诸多结构体来联合描述,如struct device,struct device_type,struct class,struct device_driver,struct bus_type等。kernel/include/linux/devices.h中有这几中结构体的定义,这里只列出和PM有关的项,其余查看源码:struct device.struct dev_pm_infopower; .struct device_type .int (*uevent)(struct device *dev, struct kobj_uevent_env *env);char *(*devnode)(struct device *dev, mode_t *mode);void (*release)(struct device *dev);const struct dev_pm_ops *pm;struct class .void (*class_release)(struct class *class);void (*dev_release)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;.;struct device_driver .int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct dev_pm_ops *pm;.;struct bus_type .int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;.;以上可以看出和电源管理相关的两个结构体是struct dev_pm_info和struct dev_pm_ops,他们定义于文件kernel/include/linux/pm.hstruct dev_pm_info pm_message_tpower_state;unsigned intcan_wakeup:1;unsigned intshould_wakeup:1;enum dpm_statestatus;/* Owned by the PM core - 表示该设备当前的PM状态*/#ifdef CONFIG_PM_SLEEPstruct list_headentry;/* 链接到dpm_list全局链表中的连接体 */#endif#ifdef CONFIG_PM_RUNTIME/ undefstruct timer_listsuspend_timer;unsigned longtimer_expires;struct work_structwork;wait_queue_head_twait_queue;spinlock_tlock;atomic_tusage_count;atomic_tchild_count;unsigned intdisable_depth:3;unsigned intignore_children:1;unsigned intidle_notification:1;unsigned intrequest_pending:1;unsigned intdeferred_resume:1;enum rpm_requestrequest;enum rpm_statusruntime_status;intruntime_error;#endif;struct dev_pm_ops int (*prepare)(struct device *dev);void (*complete)(struct device *dev);int (*suspend)(struct device *dev);int (*resume)(struct device *dev);int (*freeze)(struct device *dev);int (*thaw)(struct device *dev);int (*poweroff)(struct device *dev);int (*restore)(struct device *dev);int (*suspend_noirq)(struct device *dev);int (*resume_noirq)(struct device *dev);int (*freeze_noirq)(struct device *dev);int (*thaw_noirq)(struct device *dev);int (*poweroff_noirq)(struct device *dev);int (*restore_noirq)(struct device *dev);int (*runtime_suspend)(struct device *dev);int (*runtime_resume)(struct device *dev);int (*runtime_idle)(struct device *dev);二、device中的dev_pm_info结构体device结构体中的power项用来将该设备纳入电源管理的范围,记录电源管理的一些信息。在注册设备的时候调用函数device_add()来向sysfs系统添加power接口和注册进电源管理系统,代码片段如下:.error = dpm_sysfs_add(dev);kernel/drivers/base/power/sysfs.cif (error)goto DPMError;device_pm_add(dev);kernel/drivers/base/power/main.c.其中dpm_sysfs_add()函数用来向sysfs文件系统中添加相应设备的power接口文件,如注册mt6516_tpd paltform device的时候,会在sysfs中出现如下目录和文件:#pwd/sys/devices/platform/mt6516-tpd#cd mt6516-tpd#ls -l-rw-r-r- root root 4096 2010-01-02 06:35 uevent-r-r-r- root root 4096 2010-01-02 06:39 modaliaslrwxrwxrwx root root 2010-01-02 06:39 subsystem - ./././bus/platformdrwxr-xr-x root root 2010-01-02 06:35 powerlrwxrwxrwx root root 2010-01-02 06:39 driver - ./././bus/platform/drivers/mt6516-tpd#cd power#l
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论