您的位置:首页 > 移动开发 > Android开发

Android wakelock 学习总结第三篇

2015-03-04 18:11 204 查看
http://slightsnow.blog.chinaunix.net/uid-29269256-id-4093367.html

从这篇开始我就开始对android下的wakelock和suspend是如何结合做些自己的分析,长话短说吧,我们首先看看个函数:

路径如下:

kernel/kernel/power/main.c

这个函数就是Native曾调用的接口程序,比如:state, wakelock , unwakelock,这里都有具体实现,下面我们先分析下wake_lock相关函数,上锁过程:

(注意我只分析store函数 show函数我就不分析了)

456 static ssize_t wake_lock_store(struct kobject *kobj,

457 struct kobj_attribute *attr,

458 const char *buf, size_t n)

459 {

460 int error = pm_wake_lock(buf);

461 return error ? error : n;

462 }

这端函数没有什么可说的,就是直接把上层申请的锁名称传到pm_wake_lock中,比如 mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService"); 中的PowerManagerService。我们继续看下pm_wake_lock函数,

183 int pm_wake_lock(const char *buf)

184 {

185 const char *str = buf;

186 struct wakelock *wl;

187 u64 timeout_ns = 0;

188 size_t len;

189 int ret = 0;

190

191 while (*str && !isspace(*str))

192 str++;

193

194 len = str - buf;

195 if (!len)

196 return -EINVAL;

197

198 if (*str && *str != '\n') {

199 /* Find out if there's a valid timeout string appended. */

200 ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);

201 if (ret)

202 return -EINVAL;

203 }

204

205 mutex_lock(&wakelocks_lock);

206

207 wl = wakelock_lookup_add(buf, len, true);

208 if (IS_ERR(wl)) {

209 ret = PTR_ERR(wl);

210 goto out;

211 }

212 if (timeout_ns) {

213 u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;

214

215 do_div(timeout_ms, NSEC_PER_MSEC);

216 __pm_wakeup_event(&wl->ws, timeout_ms);

217 } else {

218 __pm_stay_awake(&wl->ws);

219 }

220

221 wakelocks_lru_most_recent(wl);

222

223 out:

224 mutex_unlock(&wakelocks_lock);

225 return ret;

226 }

这端函数主要功能在于检查这个wakelock是否存在红黑二叉树上,把名字短的放在左叉,名字长的放在右叉,这里是不是跟进程调度的二叉树很像?^_^,然后调用__pm_wakeup_event或者__pm_stay_awake函数,这里的timeout_ms我没有看明白怎么取得的,烦人,以后慢慢看看再。继续跟踪没有timeout_ms的函数吧,另外的函数进入也干了同样的事情,还对timeout进行了一些处理,可能和两种锁有关系哦?一种是带timeout时间的锁,到时会注销,一种是不带时间锁,如果没有显示的unlock就不会放弃锁。

418 void __pm_stay_awake(struct wakeup_source *ws)

419 {

420 unsigned long flags;

421

422 if (!ws)

423 return;

424

425 spin_lock_irqsave(&ws->lock, flags);

426

427 wakeup_source_report_event(ws);

428 del_timer(&ws->timer);

429 ws->timer_expires = 0;

430

431 spin_unlock_irqrestore(&ws->lock, flags);

432 }

这个函数主要干的就是调用wakeup_source_report_evet这个函数

01 static void wakeup_source_report_event(struct wakeup_source *ws)

402 {

403 ws->event_count++;

404 /* This is racy, but the counter is approximate anyway. */

405 if (events_check_enabled)

406 ws->wakeup_count++;

407

408 if (!ws->active)

409 wakeup_source_activate(ws);

381 static void wakeup_source_activate(struct wakeup_source *ws)

382 {

383 unsigned int cec;

384

385 ws->active = true;

386 ws->active_count++;

387 ws->last_time = ktime_get();

388 if (ws->autosleep_enabled)

389 ws->start_prevent_time = ws->last_time;

390

391 /* Increment the counter of events in progress. */

392 cec = atomic_inc_return(&combined_event_count);

393

394 trace_wakeup_source_activate(ws->name, cec);

395 }

这两段函数连续看,会发现,对与一些count进行的++,设置了下wake_lock中的wake_source的一些变量,主要是 对于combined_event_count这个变量进行的原子操作++,(这个变量暂时理解胃是记录有多少个wakelock吧),然后就完活了啊,这样就对一个wakelock进行。

我们再分析下wake_unlock_store这个函数,

473 static ssize_t wake_unlock_store(struct kobject *kobj,

474 struct kobj_attribute *attr,

475 const char *buf, size_t n)

476 {

477 int error = pm_wake_unlock(buf);

478 return error ? error : n;

479 }

操作一样,把写到节点的字符串传到pm_wake_unlock(buf)函数中

228 int pm_wake_unlock(const char *buf)

229 {

230 struct wakelock *wl;

231 size_t len;

232 int ret = 0;

233

234 len = strlen(buf);

235 if (!len)

236 return -EINVAL;

237

238 if (buf[len-1] == '\n')

239 len--;

240

241 if (!len)

242 return -EINVAL;

243

244 mutex_lock(&wakelocks_lock);

245

246 wl = wakelock_lookup_add(buf, len, false);

247 if (IS_ERR(wl)) {

248 ret = PTR_ERR(wl);

249 goto out;

250 }

251 __pm_relax(&wl->ws);

252

253 wakelocks_lru_most_recent(wl);

254 wakelocks_gc();

255

256 out:

257 mutex_unlock(&wakelocks_lock);

258 return ret;

259 }

这里也是在wake_lock二叉树查找wake_lock,然后调用__pm_relax(&wl->ws);这个函数,精髓都在这里,我们跟踪下去

535 void __pm_relax(struct wakeup_source *ws)

536 {

537 unsigned long flags;

538

539 if (!ws)

540 return;

541

542 spin_lock_irqsave(&ws->lock, flags);

543 if (ws->active)

544 wakeup_source_deactivate(ws);

545 spin_unlock_irqrestore(&ws->lock, flags);

546 }

547 EXPORT_SYMBOL_GPL(__pm_relax);

看到ws->active了吗?这个在之前上锁的时候我们定义过true哦,然后调用wakeup_source_deactivate这个函数,

478 static void wakeup_source_deactivate(struct wakeup_source *ws)

479 {

480 unsigned int cnt, inpr, cec;

481 ktime_t duration;

482 ktime_t now;

483

484 ws->relax_count++;

485 /*

486 * __pm_relax() may be called directly or from a timer function.

487 * If it is called directly right after the timer function has been

488 * started, but before the timer function calls __pm_relax(), it is

489 * possible that __pm_stay_awake() will be called in the meantime and

490 * will set ws->active. Then, ws->active may be cleared immediately

491 * by the __pm_relax() called from the timer function, but in such a

492 * case ws->relax_count will be different from ws->active_count.

493 */

494 if (ws->relax_count != ws->active_count) {

495 ws->relax_count--;

496 return;

497 }

498

499 ws->active = false;

500

501 now = ktime_get();

502 duration = ktime_sub(now, ws->last_time);

503 ws->total_time = ktime_add(ws->total_time, duration);

504 if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))

505 ws->max_time = duration;

506

507 ws->last_time = now;

508 del_timer(&ws->timer);

509 ws->timer_expires = 0;

510

511 if (ws->autosleep_enabled)

512 update_prevent_sleep_time(ws, now);

513

514 /*

515 * Increment the counter of registered wakeup events and decrement the

516 * couter of wakeup events in progress simultaneously.

517 */

518 cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);

519 trace_wakeup_source_deactivate(ws->name, cec);

520

521 split_counters(&cnt, &inpr);

522 if (!inpr && waitqueue_active(&wakeup_count_wait_queue))

523 wake_up(&wakeup_count_wait_queue);

524 }

这个函数前面我们就不看了,主要看下 521行到523行,这里split_counters实现如下

32 static atomic_t combined_event_count = ATOMIC_INIT(0);

33

34 #define IN_PROGRESS_BITS (sizeof(int) * 4)

35 #define MAX_IN_PROGRESS ((1 << IN_PROGRESS_BITS) - 1)

36

37 static void split_counters(unsigned int *cnt, unsigned int *inpr)

38 {

39 unsigned int comb = atomic_read(&combined_event_count);

40

41 *cnt = (comb >> IN_PROGRESS_BITS);

42 *inpr = comb & MAX_IN_PROGRESS;

43 }

这个原子操作不就是得到了刚才我们++combined_event_count记录的wake_lock数量的变量吗?取得32位数上的高16位数啊,这样的话难道每次都是高16位存的都是新值,而后16位都是旧值吗?这个还需要研究研究!然后我们看下后两行

522 if (!inpr && waitqueue_active(&wakeup_count_wait_queue))

523 wake_up(&wakeup_count_wait_queue);

这个就是判断wake_locks数,等待队列是否活动,然后唤醒等待队列,这个等待队列到底在哪里了?我们往后再说,这里先卖个关子 哇哈哈!

好了 现在我们wake_lock和unwake_lock都已经说了,但是他们和suspend有毛关系呢?我们继续分析state这个函数。

如果我们执行echo mem > /sys/power/state 会发生什么? 没错,手机屏幕会灭,手机会进入了earlysuspend状态,呵呵,这就是我分析第二片文章为什么要特意说下farmework 到 native 怎么把值写到这个节点的必要性了。下面我们看看函数

301 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,

302 const char *buf, size_t n)

303 {

304 suspend_state_t state;

305 int error;

306

307 error = pm_autosleep_lock();

308 if (error)

309 return error;

310

311 if (pm_autosleep_state() > PM_SUSPEND_ON) {

312 error = -EBUSY;

313 goto out;

314 }

315

316 state = decode_state(buf, n);

317 if (state < PM_SUSPEND_MAX) {

318 #ifdef CONFIG_EARLYSUSPEND

319 if (state == PM_SUSPEND_ON || valid_state(state)) {

320 error = 0;

321 request_suspend_state(state);

322 }

323 #else

324 error = pm_suspend(state);

325 #endif

326

327 }

328 else if (state == PM_SUSPEND_MAX)

329 error = hibernate();

330 else

331 error = -EINVAL;

332

333 out:

334 pm_autosleep_unlock();

335 return error ? error : n;

336 }

首先判断系统是不是正在suspend的状态,然后检查写入的值是否有效,如果有效这里分支就是为了支持earlysuspend过能和不带earlysuspend功能,然后调用request_suspend_state(state);这个函数。移动设备默认都带earlysuspend功能

208 void request_suspend_state(suspend_state_t new_state)

209 {

210 unsigned long irqflags;

211 int old_sleep;

212 suspend_state_t prev_state;

213

214 mutex_lock(&suspend_lock);

215 prev_state = suspend_state;

216 spin_lock_irqsave(&state_lock, irqflags);

217 old_sleep = state & SUSPEND_REQUESTED;

218 if (debug_mask & DEBUG_USER_STATE) {

219 struct timespec ts;

220 struct rtc_time tm;

221 getnstimeofday(&ts);

222 rtc_time_to_tm(ts.tv_sec, &tm);

223 pr_info("request_suspend_state: %s (%d->%d) at %lld "

224 "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",

225 new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",

226 prev_state, new_state,

227 ktime_to_ns(ktime_get()),

228 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,

229 tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);

230 }

231 if (!old_sleep && new_state != PM_SUSPEND_ON) {

232 state |= SUSPEND_REQUESTED;

233 queue_up_early_suspend_work(&early_suspend_work);

234 } else if (old_sleep && new_state == PM_SUSPEND_ON) {

235 state &= ~SUSPEND_REQUESTED;

236 __pm_stay_awake(early_suspend_ws);

237 queue_up_early_suspend_work(&late_resume_work);

238 }

239 suspend_state = new_state;

240 spin_unlock_irqrestore(&state_lock, irqflags);

241 mutex_unlock(&suspend_lock);

242 }

这个函数主要就是区分是要走earlysuspend 还是lateresume,然后调用&early_suspend_work)这个工作队列,其实就是调用early_suspend函数

136 static void early_suspend(struct work_struct *work)

137 {

138 struct early_suspend *pos;

139 unsigned long irqflags;

140 int abort = 0;

141

142 mutex_lock(&early_suspend_lock);

143 spin_lock_irqsave(&state_lock, irqflags);

144 if (state == SUSPEND_REQUESTED)

145 state |= SUSPENDED;

146 else

147 abort = 1;

148 spin_unlock_irqrestore(&state_lock, irqflags);

149

150 if (abort) {

151 if (debug_mask & DEBUG_SUSPEND)

152 pr_info("early_suspend: abort, state %d\n", state);

153 mutex_unlock(&early_suspend_lock);

154 goto abort;

155 }

156

157 if (debug_mask & DEBUG_SUSPEND)

158 pr_info("early_suspend: call handlers\n");

159 list_for_each_entry(pos, &early_suspend_handlers, link) {

160 if (pos->suspend != NULL)

161 pos->suspend(pos);

162 }

163 mutex_unlock(&early_suspend_lock);

164

165 if (debug_mask & DEBUG_SUSPEND)

166 pr_info("early_suspend: after call handlers\n");

167 /* just wake up flusher to start write back and don't wait it finished*/

168 wakeup_flusher_threads(0, WB_REASON_SYNC);

169 abort:

170 spin_lock_irqsave(&state_lock, irqflags);

171 if (state == SUSPEND_REQUESTED_AND_SUSPENDED)

172 __pm_relax(early_suspend_ws);

173 spin_unlock_irqrestore(&state_lock, irqflags);

174 mod_timer(&monitor_timer, jiffies + monitor_period*HZ);

175 queue_work(suspend_wq, &suspend_work);

176 }

这里就是逐个调用平台注册过得earlysuspend函数,按照leave来调用哦,注册时候会定义,然后系统会调用 queue_work(suspend_wq, &suspend_work);这个工作队列,这个其实就是try_to_suspend,

68 static void try_to_suspend(struct work_struct *work)

69 {

70 unsigned int initial_count, final_count;

71

72 if (!pm_get_wakeup_count(&initial_count, true) ||

73 !alarm_pm_wake_check())

74 goto queue_again;

75

76 mutex_lock(&suspend_lock);

77

78 if (!pm_save_wakeup_count(initial_count)) {

79 mutex_unlock(&suspend_lock);

80 goto queue_again;

81 }

82 del_timer_sync(&monitor_timer);

83

84 if (suspend_state == PM_SUSPEND_ON) {

85 mutex_unlock(&suspend_lock);

86 return;

87 }

88

89 if (suspend_state >= PM_SUSPEND_MAX)

90 hibernate();

91 else

92 pm_suspend(suspend_state);

93

94 mutex_unlock(&suspend_lock);

95

96 if (!pm_get_wakeup_count(&final_count, false))

97 goto queue_again;

98

99 /*

100 * If the wakeup occured for an unknown reason, wait to prevent the

101 * system from trying to suspend and waking up in a tight loop.

102 */

103 if (final_count == initial_count)

104 schedule_timeout_uninterruptible(HZ / 2);

105

106 queue_again:

107 queue_work(suspend_wq, &suspend_work);

108 }

函数嘴开始就执行了 pm_get_wakeup_count()这个函数,这个函数:

722 bool pm_get_wakeup_count(unsigned int *count, bool block)

723 {

724 unsigned int cnt, inpr;

725

726 if (block) {

727 DEFINE_WAIT(wait);

728

729 for (;;) {

730 prepare_to_wait(&wakeup_count_wait_queue, &wait,

731 TASK_INTERRUPTIBLE);

732 split_counters(&cnt, &inpr);

733 if (inpr == 0 || signal_pending(current))

734 break;

735

736 schedule();

737 }

738 finish_wait(&wakeup_count_wait_queue, &wait);

739 }

740

741 split_counters(&cnt, &inpr);

742 *count = cnt;

743 return !inpr;

744 }

看到了刚才我们介绍unwake_lock函数的时候碰见的wakeup_count_wait_queue等待队列了吧,没错,这里就循环等待是不是有应用或者driver拿着锁,如果拿着就调度出去做别的事情,等待unwake_lock的显示唤醒队列,然后再去检查split_counters(&cnt, &inpr);锁数量,如果没有锁了,OK,我们跳出循环,准备进入下面的suspend流程,到这里是不是就算解释清楚,wakelock和suspend的关系了呢?上层
中层 底层调用基本上已经联系一起了,我会在下篇文章继续分析suspend的流程!

还是一样,本人小菜鸟一名,如果不对,请指出,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: