Android wakelock可以被内核空间和用户空间 申请和释放。申请的是非超时锁,需要相应的调用wake_unlock来释放,而超时锁则不需要手工释放(当然你也可以手工释放),超时后kernel系统会自动释放锁
在内核空间可以直接调用wake_lock, wake_lock_timeout 申请锁
Android kernel为用户空间提供了申请和释放wakelock的接口,实现在kernel/power/userwakelock.c中,下面我们简单的分析下这个文件,userwakelock中仅仅涉及到用户空间操作的锁,所有锁通过红黑树进行管理,在这里就不对红黑树的操作进行分析了。
用户空间访问接口:
/sys/power/wake_lock
/sys/power/wake_unlock
129 ssize_t wake_lock_show(
130 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
131 {
132 char *s = buf;
133 char *end = buf + PAGE_SIZE;
134 struct rb_node *n;
135 struct user_wake_lock *l;
136
137 mutex_lock(&tree_lock);
138
139 for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
140 l = rb_entry(n, struct user_wake_lock, node);
141 if (wake_lock_active(&l->wake_lock))
142 s += scnprintf(s, end - s, "%s ", l->name);
143 }
144 s += scnprintf(s, end - s, "\n");
145
146 mutex_unlock(&tree_lock);
147 return (s - buf);
148 }
显示应用空间申请的所有激活锁(包括超时锁和非超时锁)
150 ssize_t wake_lock_store(
151 struct kobject *kobj, struct kobj_attribute *attr,
152 const char *buf, size_t n)
153 {
154 long timeout;
155 struct user_wake_lock *l;
156
157 mutex_lock(&tree_lock);
158 l = lookup_wake_lock_name(buf, 1, &timeout);
159 if (IS_ERR(l)) {
160 n = PTR_ERR(l);
161 goto bad_name;
162 }
163
164 if (debug_mask & DEBUG_ACCESS)
165 pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
166
167 if (timeout)
168 wake_lock_timeout(&l->wake_lock, timeout);
169 else
170 wake_lock(&l->wake_lock);
171 bad_name:
172 mutex_unlock(&tree_lock);
173 return n;
174 }
申请一把锁,名字以及超时时间都包含在参数@buf中,lookup_wake_lock_name会解析出名字和超时时间,如果超时时间不存在说明申请的是非超时锁,否则是超时锁
167~170 调用wake_lock申请非超时锁;调用wake_lock_timeout申请非超时锁。
177 ssize_t wake_unlock_show(
178 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
179 {
180 char *s = buf;
181 char *end = buf + PAGE_SIZE;
182 struct rb_node *n;
183 struct user_wake_lock *l;
184
185 mutex_lock(&tree_lock);
186
187 for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
188 l = rb_entry(n, struct user_wake_lock, node);
189 if (!wake_lock_active(&l->wake_lock))
190 s += scnprintf(s, end - s, "%s ", l->name);
191 }
192 s += scnprintf(s, end - s, "\n");
193
194 mutex_unlock(&tree_lock);
195 return (s - buf);
196 }
该函数显示当前应用空间可申请的所有未激活锁(包括超时锁和非超时锁),打印出锁的名字,返回给用户空间。
187 遍历整个RB树,
199 struct kobject *kobj, struct kobj_attribute *attr,
200 const char *buf, size_t n)
201 {
202 struct user_wake_lock *l;
203
204 mutex_lock(&tree_lock);
205 l = lookup_wake_lock_name(buf, 0, NULL);
206 if (IS_ERR(l)) {
207 n = PTR_ERR(l);
208 goto not_found;
209 }
210
211 if (debug_mask & DEBUG_ACCESS)
212 pr_info("wake_unlock_store: %s\n", l->name);
213
214 wake_unlock(&l->wake_lock);
215 not_found:
216 mutex_unlock(&tree_lock);
217 return n;
218 }
205 用户空间接口按照RB(红黑树)来组织wakelock锁,这样可以加快查找速度,第三个参数为NULL,因为wake_unlock_store仅仅针对非超时锁,超时锁不需要unlock
214 调用wake_unlock释放非超时锁
如果用命令
#echo "kaka 12" > /sys/power/wake_lock
申请一个超时锁,那么在超时后,执行
#cat /sys/power/wake_lock
kaka
显示这个超时锁还存在,觉得这个接口有问题。