-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
1139 lines (942 loc) · 737 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>生活不止眼前的代码</title>
<link href="/atom.xml" rel="self"/>
<link href="http://robinheztto.com/"/>
<updated>2018-10-15T14:58:13.000Z</updated>
<id>http://robinheztto.com/</id>
<author>
<name>Robin He</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Overview</title>
<link href="http://robinheztto.com/2200/01/01/android-overview/"/>
<id>http://robinheztto.com/2200/01/01/android-overview/</id>
<published>2199-12-31T16:00:00.000Z</published>
<updated>2018-10-15T14:58:13.000Z</updated>
<content type="html"><blockquote>
<p>Android学习提纲.从底至上.RTFSC.<strong>持续学习整理中…</strong></p>
</blockquote>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/android_framework_details.png?raw=true" alt="Android stack"><br></div>
<h1 id="BootFlow"><a href="#BootFlow" class="headerlink" title="BootFlow"></a>BootFlow</h1><ul>
<li><a href="http://www.robinheztto.com/2016/01/15/android-lk/" target="_blank" rel="external">Android之BootFlow</a></li>
<li><a href="http://www.robinheztto.com/2016/01/15/android-lk/" target="_blank" rel="external">Android之LK</a></li>
<li>[Android之Recovery]</li>
<li><a href="http://www.robinheztto.com/2016/02/01/android-init-language/" target="_blank" rel="external">Android之Init.rc语法</a></li>
<li><a href="http://www.robinheztto.com/2016/02/02/android-init/" target="_blank" rel="external">Android之Init</a></li>
<li><a href="http://www.robinheztto.com/2016/07/01/android-zygote-1/" target="_blank" rel="external">Android之Zygote-启动流程</a></li>
<li><a href="http://www.robinheztto.com/2016/07/02/android-zygote-2/" target="_blank" rel="external">Android之Zygote-应用进程创建</a></li>
<li><a href="http://www.robinheztto.com/2016/11/28/android-systemserver-1/" target="_blank" rel="external">Android之SystemServer启动(上)</a></li>
<li><a href="http://www.robinheztto.com/2016/11/28/android-systemserver-2/" target="_blank" rel="external">Android之SystemServer启动(下)</a></li>
</ul>
<hr>
<h1 id="PowerManagerment"><a href="#PowerManagerment" class="headerlink" title="PowerManagerment"></a>PowerManagerment</h1><ul>
<li><a href="http://www.robinheztto.com/2017/04/20/android-power-basic/" target="_blank" rel="external">Android电源管理系列之Basic</a></li>
<li><a href="http://www.robinheztto.com/2017/05/01/android-power-system-wakeup-events-framework/" target="_blank" rel="external">Android电源管理系列之System wakeup events framework</a></li>
<li><a href="http://www.robinheztto.com/2017/05/05/android-power-suspend/" target="_blank" rel="external">Android电源管理系列之Suspend</a></li>
<li><a href="http://www.robinheztto.com/2017/05/20/android-power-libsuspend/" target="_blank" rel="external">Android电源管理系列之libsuspend</a></li>
<li><a href="http://www.robinheztto.com/2017/06/01/android-power-wakelock/" target="_blank" rel="external">Android电源管理系列之Wakelock</a></li>
<li><a href="http://www.robinheztto.com/2017/06/14/android-power-pms-1/" target="_blank" rel="external">Android电源管理系列之PowerManagerService(一)</a></li>
<li><a href="http://www.robinheztto.com/2017/06/16/android-power-pms-2/" target="_blank" rel="external">Android电源管理系列之PowerManagerService(二)</a></li>
<li><a href="http://www.robinheztto.com/2017/09/11/android-power-doze-overview/" target="_blank" rel="external">Android电源管理系列之Doze</a></li>
<li><a href="http://www.robinheztto.com/2017/09/13/android-power-doze-light/" target="_blank" rel="external">Android电源管理系列之Light Doze</a></li>
<li><a href="http://www.robinheztto.com/2017/09/15/android-power-doze-deep/" target="_blank" rel="external">Android电源管理系列之Deep Doze</a></li>
</ul>
<hr>
<h1 id="Binder"><a href="#Binder" class="headerlink" title="Binder"></a>Binder</h1><ul>
<li><a href="http://www.robinheztto.com/2016/03/19/android-binder-0/" target="_blank" rel="external">Android Binder之概述</a></li>
<li><a href="http://www.robinheztto.com/2016/03/20/android-binder-1/" target="_blank" rel="external">Android Binder之Binder Driver</a></li>
<li><a href="http://www.robinheztto.com/2016/03/25/android-binder-2/" target="_blank" rel="external">Android Binder之Service Manager</a></li>
<li><a href="http://www.robinheztto.com/2016/03/28/android-binder-3/" target="_blank" rel="external">Android Binder之进程间通信库</a></li>
<li><a href="http://www.robinheztto.com/2016/03/28/android-binder-4/" target="_blank" rel="external">Android Binder之Service Manager代理对象</a></li>
<li><a href="http://www.robinheztto.com/2016/04/02/android-binder-5/" target="_blank" rel="external">Android Binder之Service启动</a></li>
<li><a href="http://www.robinheztto.com/2016/04/18/android-binder-6/" target="_blank" rel="external">Android Binder之Service代理获取</a></li>
<li><a href="http://www.robinheztto.com/2016/04/23/android-binder-7/" target="_blank" rel="external">Android Binder之Java接口</a></li>
</ul>
<hr>
<h1 id="Frameworks"><a href="#Frameworks" class="headerlink" title="Frameworks"></a>Frameworks</h1><ul>
<li><a href="http://www.robinheztto.com/2016/01/01/android-env/" target="_blank" rel="external">Android之Zygote-启动流程</a></li>
<li><a href="http://www.robinheztto.com/2016/01/01/android-env/" target="_blank" rel="external">Android之Zygote-应用进程创建</a></li>
<li><a href="http://www.robinheztto.com/2016/02/02/android-init/" target="_blank" rel="external">Android之SystemServer启动(上)</a></li>
<li><a href="http://www.robinheztto.com/2016/02/02/android-init/" target="_blank" rel="external">Android之SystemServer启动(下)</a></li>
<li><a href="http://www.robinheztto.com/2017/03/10/android-alarm-1/" target="_blank" rel="external">Android之AlarmManagerService(一)</a></li>
<li><a href="http://www.robinheztto.com/2017/03/11/android-alarm-2/" target="_blank" rel="external">Android之AlarmManagerService(二)</a></li>
<li><a href="http://www.robinheztto.com/2017/03/12/android-alarm-3/" target="_blank" rel="external">Android之AlarmManagerService(三)</a></li>
</ul>
<hr>
<h1 id="APP"><a href="#APP" class="headerlink" title="APP"></a>APP</h1><ul>
<li><a href="http://www.robinheztto.com/2014/08/01/android-basis-activity/" target="_blank" rel="external">Android应用开发基础之Activity</a></li>
<li><a href="http://www.robinheztto.com/2014/08/03/android-basis-service/" target="_blank" rel="external">Android应用开发基础之Service</a></li>
</ul>
<hr>
<h1 id="CI持续集成"><a href="#CI持续集成" class="headerlink" title="CI持续集成"></a>CI持续集成</h1><ul>
<li><a href="http://www.robinheztto.com/2018/06/14/android-ci-gitolite/" target="_blank" rel="external">Android编译集成之gitolite</a></li>
<li><a href="http://www.robinheztto.com/2018/05/19/android-build-sign/" target="_blank" rel="external">Android编译之签名机制</a></li>
<li><a href="http://www.robinheztto.com/2018/05/03/android-ci-jenkins/" target="_blank" rel="external">Android持续集成之Jenkins</a></li>
<li><a href="http://www.robinheztto.com/2015/08/03/ubuntu-nexus-maven/" target="_blank" rel="external">Ubuntu 14.04 Nexus Maven私服搭建</a></li>
<li><a href="http://www.robinheztto.com/2015/06/06/ubuntu-ftp/" target="_blank" rel="external">Ubuntu14.04 FTP服务器搭建</a></li>
<li><a href="http://www.robinheztto.com/2015/03/18/remastersys-md/" target="_blank" rel="external">remastersys 备份/制作ubuntu副本</a></li>
<li><a href="http://www.robinheztto.com/2015/05/23/git-operate/" target="_blank" rel="external">git操作总结</a></li>
</ul>
<hr>
<h1 id="Java"><a href="#Java" class="headerlink" title="Java"></a>Java</h1><p>Java系列之经典问答<br>Java系列之对象创建过程<br>Java系列之ThreadLocal<br>Java多线程之Volatile<br>Java多线程之synchronized<br>Java多线程之线程基础<br>Java系列之内存模型<br>Java系列之LinkedList解析<br>Java系列之ArrayList解析<br>Java系列之集合框架总结<br>Java系列之常量池总结<br>Java系列之JVM运行时数据区<br>Java系列之引用<br>Java系列之抽象类与接口<br>Java系列之关键字总结<br>Java系列之异常处理机制总结<br>Java系列之对Java平台的理解</p>
<hr>
<h1 id="Debug"><a href="#Debug" class="headerlink" title="Debug"></a>Debug</h1><ul>
<li><a href="http://www.robinheztto.com/2016/01/01/android-env/" target="_blank" rel="external">Android Debug之系统启动</a></li>
<li><a href="http://www.robinheztto.com/2017/03/08/android-debug-anr/" target="_blank" rel="external">Android Debug之ANR</a></li>
<li><a href="http://www.robinheztto.com/2016/11/12/android-debug-adb/" target="_blank" rel="external">Android Debug之ADB</a></li>
</ul>
<hr>
<h1 id="Env-amp-Tools"><a href="#Env-amp-Tools" class="headerlink" title="Env&amp;Tools"></a>Env&amp;Tools</h1><ul>
<li><p><a href="http://www.robinheztto.com/2016/01/01/android-env/" target="_blank" rel="external">Android之开发环境搭建</a></p>
</li>
<li><p><a href="http://www.robinheztto.com/2016/01/05/android-tcpdump/" target="_blank" rel="external">Android之抓包</a></p>
</li>
</ul>
<hr>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><ul>
<li><a href="http://free-electrons.com/pub/conferences/2012/captronic/android/android-captronic.pdf" target="_blank" rel="external">android-captronic</a></li>
</ul>
</content>
<summary type="html">
<blockquote>
<p>Android学习提纲.从底至上.RTFSC.<strong>持续学习整理中…</strong></p>
</blockquote>
<div align="center"><br><img src="https://github.com/Robi
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
</entry>
<entry>
<title>Android#Issue</title>
<link href="http://robinheztto.com/2100/01/01/android-issue/"/>
<id>http://robinheztto.com/2100/01/01/android-issue/</id>
<published>2099-12-31T16:00:00.000Z</published>
<updated>2016-12-25T12:27:10.000Z</updated>
<content type="html"><p><strong>关于Android N平台java.lang.UnsatisfiedLinkError: dlopen failed的问题</strong></p>
<blockquote>
<p>Android N上应用Crash,log上报java.lang.UnsatisfiedLinkError,类似如下的log:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">java.lang.UnsatisfiedLinkError: dlopen failed: library &quot;libcutils.so&quot;</span><br><span class="line">(&quot;/system/lib/libcutils.so&quot;) needed or dlopened by</span><br><span class="line">&quot;/system/lib/libnativeloader.so&quot; is not accessible for the namespace</span><br><span class="line">&quot;classloader-namespace&quot;</span><br><span class="line"> at java.lang.Runtime.loadLibrary0(Runtime.java:977)</span><br><span class="line"> at java.lang.System.loadLibrary(System.java:1602)</span><br></pre></td></tr></table></figure></p>
<p>原因:<br>从Android N开始,系统将阻止应用动态链接非公开NDK库(参考官网描述<a href="https://developer.android.com/about/versions/nougat/android-7.0-changes.html" target="_blank" rel="external">android-7.0-changes</a>)<br>解决:<br> 1. so库打包到apk里面或参考官网解决<br> 2. 添加so到public.libraries.txt白名单.(参考<a href="http://blog.csdn.net/xiashaohua/article/details/52709630?utm_source=itdadao&amp;utm_medium=referral" target="_blank" rel="external">android N : UnsatisfiedLinkError</a>)</p>
</blockquote>
<hr>
<p><strong>关于绕过默认短信应用限制读写短信的问题</strong></p>
<blockquote>
<p>Android 4.4以后,只有默认短信应用才具有读写短信的权限,系统应用比如垃圾短信拦截,一键换机等需要在未设置为默认短信应用的情况下读写短信数据库,可以利用以下代码实现:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">if ( 19 &gt;= Build.VERSION.SDK_INT) &#123;</span><br><span class="line"> try &#123;</span><br><span class="line"> AppOpsManager appOpsManager = (AppOpsManager) sContext.getSystemService(&quot;appops&quot;);</span><br><span class="line"> appOpsManager.setMode(15, android.os.Process.myUid(), packageName, 0);</span><br><span class="line"> &#125; catch (Exception e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</blockquote>
<p>具体原理参考<a href="http://3dobe.com/archives/51/" target="_blank" rel="external">Android 权限管理 AppOps</a></p>
<hr>
<p><strong>关于使用jack编译生成jar包</strong></p>
<blockquote>
<p>Jack是Java Android Compiler Kit的缩写,它直接将Java代码直接编译为字节码,不再生成classes.jar等中间文件,而是直接生成了classes.jack文件,需生成classes.jar时,可在Android.mk中添加如下定义:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LOCAL_JACK_ENABLED=disabled</span><br></pre></td></tr></table></figure></p>
</blockquote>
<p>Jack &amp; Jill参考<a href="https://yq.aliyun.com/articles/40811" target="_blank" rel="external">Android 新一代编译 toolchain Jack &amp; Jill 简介</a></p>
<hr>
<p><strong>关于Android Gradle Plugin</strong></p>
<blockquote>
<p>编译android gradle plugin</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$ mkdir studio-master-dev</span><br><span class="line">$ cd studio-master-dev</span><br><span class="line">$ repo init -u https://android.googlesource.com/platform/manifest -b studio-master-dev</span><br><span class="line">$ repo sync</span><br><span class="line">$ cd tools</span><br><span class="line">$ ./gradlew init</span><br><span class="line">$ ./gradlew assemble</span><br><span class="line">$ ./gradlew publishLocal</span><br></pre></td></tr></table></figure>
<blockquote>
<p>关于gradle不支持不支持msgid同名字符串的问题(由于不是标准Application做法)参考gradle plugin源码:</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">sdk-common/src/main/java/com/android/ide/common/res2/ValueResourceParser2.java</span><br><span class="line">checkDuplicate() -&gt;</span><br><span class="line">else if (set.contains(name) &amp;&amp; resource.getType() != ResourceType.PUBLIC) &#123;</span><br><span class="line"> System.out.println(&quot;checkDuplicate ------&gt; &quot; + resource.getType());</span><br><span class="line"> throw MergingException.withMessage(</span><br><span class="line"> &quot;Found item %s/%s more than one time&quot;,</span><br><span class="line"> resource.getType().getDisplayName(), name).withFile(from).build();</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>
<p><a href="https://groups.google.com/forum/#!topic/android-building/dxP0tp0e1MI" target="_blank" rel="external">Gradle vs. Make for AOSP build</a><br><a href="http://tools.android.com/tech-docs" target="_blank" rel="external">Android Gradle</a></p>
</content>
<summary type="html">
<p><strong>关于Android N平台java.lang.UnsatisfiedLinkError: dlopen failed的问题</strong></p>
<blockquote>
<p>Android N上应用Crash,log上报java.lang.Unsat
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
</entry>
<entry>
<title>Kotlin开篇</title>
<link href="http://robinheztto.com/2018/10/01/kotlin-1/"/>
<id>http://robinheztto.com/2018/10/01/kotlin-1/</id>
<published>2018-10-01T00:12:10.000Z</published>
<updated>2019-03-27T14:54:02.000Z</updated>
<content type="html"><blockquote>
<p>Kotlin是一种静态类型、面向对象,旨在避免Java向后兼容性问题,基于JVM的现代编程语言。<a href="https://www.jetbrains.com/" target="_blank" rel="external">JetBrains公司</a>(开发了号称Java界最智能的集成开发工具IntelliJ IDEA的公司)于2010年开发出该编程语言并于2012年2月宣布将其开源。Kotlin语言最初设计的目的是替代Java语言。在2017 Google I/O上,Google正式宣布Kotlin为Android官方开发语言。</p>
</blockquote>
<h1 id="Kotlin的优势"><a href="#Kotlin的优势" class="headerlink" title="Kotlin的优势"></a>Kotlin的优势</h1><ul>
<li>完全兼容Java</li>
<li>Null safe</li>
<li>支持lambda表达式(比Java8更好)</li>
<li>支持扩展</li>
<li>体验一致的开发工具链</li>
</ul>
<p>对于开发者来说:</p>
<ul>
<li>更少的空指针异常</li>
<li>更少的代码量</li>
<li>更快的开发速度</li>
<li>更一致的开发体验</li>
</ul>
<h1 id="命令行工具"><a href="#命令行工具" class="headerlink" title="命令行工具"></a>命令行工具</h1><ol>
<li><p>下载kotlin-compiler工具包并配置到环境变量路径</p>
<blockquote>
<p>下载路径:<a href="https://github.com/JetBrains/kotlin/releases/tag/v1.1.2-2(可使用最新release)" target="_blank" rel="external">https://github.com/JetBrains/kotlin/releases/tag/v1.1.2-2(可使用最新release)</a></p>
</blockquote>
</li>
<li><p>使用 Kotlin 编译器编译应用:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ kotlinc hello.kt -include-runtime -d hello.jar</span><br></pre></td></tr></table></figure>
</li>
<li><p>运行应用:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ java -jar hello.jar</span><br></pre></td></tr></table></figure>
</li>
<li><p>Kotlin库编译<br>如果需要将生成的jar包供其他Kotlin程序使用,无需包含Kotlin的运行库:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ kotlinc hello.kt -d hello.jar</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1 id="参考连接"><a href="#参考连接" class="headerlink" title="参考连接"></a>参考连接</h1><ul>
<li><a href="https://kotlinlang.org/" target="_blank" rel="external">Kotlin官方网站</a></li>
<li><a href="https://try.kotlinlang.org/" target="_blank" rel="external">Kotlin官方教程</a></li>
</ul>
</content>
<summary type="html">
<blockquote>
<p>Kotlin是一种静态类型、面向对象,旨在避免Java向后兼容性问题,基于JVM的现代编程语言。<a href="https://www.jetbrains.com/" target="_blank" rel="external">JetBrain
</summary>
<category term="Kotlin" scheme="http://robinheztto.com/tags/Kotlin/"/>
</entry>
<entry>
<title>Android App系列之CoordinatorLayout嵌套双层RecyclerView</title>
<link href="http://robinheztto.com/2018/09/11/android-CoordinatorLayout-RecyclerView/"/>
<id>http://robinheztto.com/2018/09/11/android-CoordinatorLayout-RecyclerView/</id>
<published>2018-09-11T06:47:22.000Z</published>
<updated>2018-10-15T14:58:13.000Z</updated>
<content type="html"><h1 id="CoordinatorLayout嵌套RecyclerView无法点击的问题"><a href="#CoordinatorLayout嵌套RecyclerView无法点击的问题" class="headerlink" title="CoordinatorLayout嵌套RecyclerView无法点击的问题"></a>CoordinatorLayout嵌套RecyclerView无法点击的问题</h1><p>CoordinatorLayout嵌套RecyclerView,RecyclerView滚动后第一次无法点击,问题原因是RecyclerView的scrollState。当它停止滚动时,它不会立即更改scrollState为SCROLL_STATE_IDLE。当RecyclerView滚动停止后,它不立即调用setScrollState(SCROLL_STATE_IDLE),而是等待一段时间来触发此方法。滚动越快,需等待的时间就越多。scroller.isFinished()在RecyclerView停止滚动触摸顶部之后不会立即返回true。</p>
<p>该问题是源码的bug,问题跟踪:<br><a href="https://developer.android.com/topic/libraries/support-library/revisions.html#27-0-1" target="_blank" rel="external">https://developer.android.com/topic/libraries/support-library/revisions.html#27-0-1</a><br>After a user scrolls, they cannot click on an item in a RecyclerView. (AOSP issue 66996774)</p>
<p>一些用户报告在支持库27.0.1中没有修复此问题。<br>问题跟踪器在这里。<br><a href="https://issuetracker.google.com/issues/66996774" target="_blank" rel="external">https://issuetracker.google.com/issues/66996774</a></p>
<p><strong>官方解决方案</strong><br><a href="https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2" target="_blank" rel="external">https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2</a></p>
<h1 id="CoordinatorLayout嵌套RecyclerView无法滑动的问题"><a href="#CoordinatorLayout嵌套RecyclerView无法滑动的问题" class="headerlink" title="CoordinatorLayout嵌套RecyclerView无法滑动的问题"></a>CoordinatorLayout嵌套RecyclerView无法滑动的问题</h1><p><strong><em>解决方式:为横向RecyclerView增加一句setNestedScrollingEnabled(false)</em></strong><br>CoordinatorLayout实现了NestedScrollingParent,纵向RecyclerView是CoordinatorLayout的子View,RecyclerView的滑动能通知到CoordinatorLayout,继而由CoordinatorLayout协调让CollapsingToolbarLayout发生折叠。横向RecyclerView的父View是纵向RecyclerView,而RecyclerView只实现了NestedScrollingChild,无法像CoordinatorLayout一样响应。所以要关闭横向RecyclerView的嵌套滑动功能,让横向RecyclerView如同其他嵌入纵向RecyclerView的view一样,触发折叠。</p>
<h1 id="嵌套RecyclerView的优化"><a href="#嵌套RecyclerView的优化" class="headerlink" title="嵌套RecyclerView的优化"></a>嵌套RecyclerView的优化</h1><p>在一个RecyclerView中嵌套另一个RecyclerView,类似下面的横向滚动列表嵌套垂直滚动列表的形式。</p>
<center><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/android-nesting-recycleview.webp?raw=true" alt=""><br></center>
<p>当用户滚动横向列表的时候,inner RecyclerView可以流畅的滚动。但是当垂直滚动的时候,inner RecyclerView中的每个view再次inflated了一遍,从而感觉很卡顿。这是因为每个嵌套的RecyclerViews都有各自的view pool。</p>
<p><strong>优化:</strong><br>为所有inner RecyclerView设置一个单一的view pool,减少了view的创建,提高了滚动性能<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">public OuterRecyclerViewAdapter(List&lt;Item&gt; items) &#123;</span><br><span class="line"> //Constructor stuff</span><br><span class="line"> viewPool = new RecyclerView.RecycledViewPool();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">@Override</span><br><span class="line">public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) &#123;</span><br><span class="line"> //Create viewHolder etc</span><br><span class="line"> holder.innerRecyclerView.setRecycledViewPool(viewPool);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</content>
<summary type="html">
<h1 id="CoordinatorLayout嵌套RecyclerView无法点击的问题"><a href="#CoordinatorLayout嵌套RecyclerView无法点击的问题" class="headerlink" title="CoordinatorLayou
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="App" scheme="http://robinheztto.com/tags/App/"/>
</entry>
<entry>
<title>Android编译集成之gitolite</title>
<link href="http://robinheztto.com/2018/06/14/android-ci-gitolite/"/>
<id>http://robinheztto.com/2018/06/14/android-ci-gitolite/</id>
<published>2018-06-14T07:01:14.000Z</published>
<updated>2018-10-15T14:58:13.000Z</updated>
<content type="html"><blockquote>
<p>在Git服务管理领域,主要有三种流行的方案:<br>Gitosis - 轻量级,开源项目,使用SSH公钥认证,只能做到库级的权限控制,目前项目已经停止开发,不再维护。<br>Gitolite - 轻量级,开源项目,使用SSH公钥认证,能做到分支级的权限控制。<br>Git + Repo + Gerrit - 超级重量级,集版本控制,库管理和代码审核为一身,可管理大型及超大型项目。</p>
</blockquote>
<p>Gitolite是在Git之上的一个授权层,依托sshd或者httpd来进行认证。Gitolite允许你定义访问许可不只作用于仓库,同样可作用于仓库中的每个branch和tag name,可确切定义用户(或一组人)只能push特定的”refs”(或者branches或者tags)。</p>
<h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><p>Gitolite的安装需要分别在客户端和服务器端操作,搭建Gitolite的步骤如下图所示。<br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/ci/gitolite.png?raw=true" alt="Gitolite"></p>
<h3 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h3><ol>
<li><p>安装openssh</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get -y install openssh-client</span><br></pre></td></tr></table></figure>
</li>
<li><p>安装git</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get -y install git</span><br></pre></td></tr></table></figure>
</li>
<li><p>生成SSH key</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ ssh-keygen -t rsa -C HF</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>运行命令后,一直按回车键直到SSH key生成。</p>
<ol>
<li>上传SSH public key到服务器<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ mv ~/.ssh/id_rsa.pub username.pub</span><br><span class="line">$ scp username.pub servername@server:/tmp</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>username及server根据实际情况填写。</p>
<h3 id="服务器"><a href="#服务器" class="headerlink" title="服务器"></a>服务器</h3><ol>
<li><p>安装openssh</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get -y install openssh-server openssh-client</span><br></pre></td></tr></table></figure>
</li>
<li><p>安装git</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get -y install git</span><br></pre></td></tr></table></figure>
</li>
<li><p>安装gitolite</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get -y install gitolite</span><br></pre></td></tr></table></figure>
</li>
<li><p>创建gitolite用户</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo adduser --system --shell /bin/bash --group --disabled-password --home /home/gitolite gitolite</span><br></pre></td></tr></table></figure>
</li>
<li><p>初始化服务</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ sudo chmod 777 /tmp/username.pub</span><br><span class="line">$ sudo su - gitolite</span><br><span class="line">$ gl-setup /tmp/username.pub</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>上面的命令执行作用:<br>a)建立目录“~/repositories”,用来存储所有git仓库。<br>b)把公钥文件username.pub添加到 ~/.ssh/authorized_keys。</p>
<h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>gitolite的配置文件本身就是一个git仓库,gitolite的配置修改就是通过git实现的,先clone下来修改,再push上去。只要push上去,gitolite会立刻监视到配置文件的修改并应用。</p>
<h3 id="管理库"><a href="#管理库" class="headerlink" title="管理库"></a>管理库</h3><p>首先,在管理客户端clone管理库到本地。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git clone gitolite@server:gitolite-admin.git</span><br></pre></td></tr></table></figure></p>
<p>管理库里的目录里有conf/和keydir/两个目录。</p>
<ul>
<li>conf/gitolite.conf 用于Git项目配置,访问权限设置。</li>
<li>keydir/ 用于存储用户的SSH public key(公钥)。</li>
</ul>
<p>如下所示, “username”(之前用gl-setup命令时候的pubkey名称)具有读写权限而且在gitolite-admin仓库里有一个同名的公钥文件。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ cat conf/gitolite.conf</span><br><span class="line"></span><br><span class="line">repo gitolite-admin</span><br><span class="line"> RW+ = username</span><br></pre></td></tr></table></figure></p>
<h3 id="配置-1"><a href="#配置-1" class="headerlink" title="配置"></a>配置</h3><ol>
<li>用户/仓库分组</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">@oss_repos = linux perl rakudo git gitolite</span><br><span class="line">@secret_repos = fenestra pear</span><br><span class="line"></span><br><span class="line">@admins = scott</span><br><span class="line">@interns = ashok</span><br><span class="line">@engineers = sitaram dilbert wally alice</span><br><span class="line">@staff = @admins @engineers @interns</span><br></pre></td></tr></table></figure>
<p>在下面的例子里,实习生可以push ”int“分支。工程师可以push任何有”eng-“开头的branch,还有refs/tags下面用”rc”开头的后面跟数字的。而且管理员可以随便更改(包括rewind)对任何参考名。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">repo @oss_repos</span><br><span class="line"> RW int$ = @interns</span><br><span class="line"> RW eng- = @engineers</span><br><span class="line"> RW refs/tags/rc[0-9] = @engineers</span><br><span class="line"> RW+ = @admins</span><br></pre></td></tr></table></figure></p>
<p>2.GL_WILDREPOS<br>在gitolite里修改权限,添加正则表达式后提交</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">repo test/.*$</span><br><span class="line">R = test</span><br></pre></td></tr></table></figure>
<p>提示 warning:<br>remote: bad reponame ‘test/.*$’ or you forgot to set $GL_WILDREPOS</p>
<p>修改服务器/home/git/.gitolite.rc设置$GL_WILDREPOS=0为$GL_WILDREPOS=1即可</p>
<h3 id="Repo仓库"><a href="#Repo仓库" class="headerlink" title="Repo仓库"></a>Repo仓库</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">#/bin/bash</span><br><span class="line"></span><br><span class="line">set -x</span><br><span class="line"></span><br><span class="line">pwd=$&#123;PWD&#125;</span><br><span class="line">QCOM=/data/QcomBaseBackup/QcomBase</span><br><span class="line"></span><br><span class="line">attrget() </span><br><span class="line">&#123;</span><br><span class="line"> ATTR_PAIR=$&#123;1#*$2=\&quot;&#125;</span><br><span class="line"> echo &quot;$&#123;ATTR_PAIR%%\&quot;*&#125;&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">parse_manifest()</span><br><span class="line">&#123;</span><br><span class="line"> local IFS=\&gt;</span><br><span class="line"></span><br><span class="line"> while read -d \&lt; ENTITY CONTENT</span><br><span class="line"> do</span><br><span class="line"> TAG_NAME=$&#123;ENTITY%% *&#125;</span><br><span class="line"> ATTRIBUTES=$&#123;ENTITY#* &#125;</span><br><span class="line"> if [[ $TAG_NAME == &quot;project&quot; ]];then</span><br><span class="line"> CLIENT_PATH=`attrget $&#123;ATTRIBUTES&#125; &quot;path&quot;`</span><br><span class="line"> SERVER_PATH=`attrget $&#123;ATTRIBUTES&#125; &quot;name&quot;`</span><br><span class="line"> if [ $SERVER_PATH == &quot;&quot; ];then</span><br><span class="line"> echo</span><br><span class="line"> else</span><br><span class="line"> if [ $CLIENT_PATH == &quot;name=&quot; ];then</span><br><span class="line"> CLIENT_PATH=$SERVER_PATH</span><br><span class="line"> fi</span><br><span class="line"> fi</span><br><span class="line"> repo_pro $SERVER_PATH $CLIENT_PATH</span><br><span class="line"> fi</span><br><span class="line"> done &lt; $1</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">repo_pro() &#123;</span><br><span class="line"> REMOTE_PATH=$1</span><br><span class="line"> LOCAL_PATH=$2</span><br><span class="line"> workdir=$pwd/$&#123;REMOTE_PATH##*/&#125;</span><br><span class="line"> echo $workdir</span><br><span class="line"> git clone [email protected]:qcom/$REMOTE_PATH</span><br><span class="line"> cd $workdir</span><br><span class="line"> git checkout -b master</span><br><span class="line"> rm -rf !\(.git\)</span><br><span class="line"> cp -rf $QCOM/$CLIENT_PATH/* $workdir</span><br><span class="line"> find . -name .gitignore | xargs rm -rfv</span><br><span class="line"> git add -A</span><br><span class="line"> git commit --allow-empty -m &quot;Initial commit update&quot;</span><br><span class="line"> git push --set-upstream origin master</span><br><span class="line"> cd $pwd</span><br><span class="line"> rm -rf $workdir</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">parse_manifest $1</span><br></pre></td></tr></table></figure></content>
<summary type="html">
<blockquote>
<p>在Git服务管理领域,主要有三种流行的方案:<br>Gitosis - 轻量级,开源项目,使用SSH公钥认证,只能做到库级的权限控制,目前项目已经停止开发,不再维护。<br>Gitolite - 轻量级,开源项目,使用SSH公钥认证,能做到分支级的
</summary>
<category term="CI" scheme="http://robinheztto.com/tags/CI/"/>
<category term="gitolite" scheme="http://robinheztto.com/tags/gitolite/"/>
</entry>
<entry>
<title>Android编译之签名机制</title>
<link href="http://robinheztto.com/2018/05/19/android-build-sign/"/>
<id>http://robinheztto.com/2018/05/19/android-build-sign/</id>
<published>2018-05-19T03:11:12.000Z</published>
<updated>2018-12-22T14:06:41.000Z</updated>
<content type="html"><blockquote>
<p>Android OS 镜像在两个地方使用加密签名:</p>
<ol>
<li>映像中的所有.apk文件都必须经过签名。Android软件包管理器通过下列两种方式使用.apk 签名:<ul>
<li>更换应用时,必须使用与旧应用相同的密钥对其签名,才能存取旧应用的数据。无论是通过覆盖.apk 来更新用户应用,还是使用安装在 /data 下的新版本应用来覆盖系统应用,这一点都适用。</li>
<li>如果两个或多个应用想要共享同一个用户 ID(方便共享数据等),则必须使用相同的密钥对它们进行签名。</li>
</ul>
</li>
<li>必须使用符合系统预期的密钥对 OTA 更新包进行签名,否则在安装过程中 OTA 更新包将被拒绝。</li>
</ol>
</blockquote>
<h1 id="密钥"><a href="#密钥" class="headerlink" title="密钥"></a>密钥</h1><p>Android源码build/target/product/security目录下提供了测试密钥,包括platform,shared,media verity,test(testkey是作为android编译的时候默认的签名key,如果代码中apk的android.mk没有设置LOCAL_CERTIFICATE的值,就默认使用testkey),其中shared.pk8是私钥,shared.x509.pem是公钥,一定是成对匹配出现的。当编译整个Android OS映像时将使用这些测试密钥对所有.apk文件进行签名。</p>
<h2 id="自定义Key"><a href="#自定义Key" class="headerlink" title="自定义Key"></a>自定义Key</h2><p>Android源码build/target/product/security/README说明了key的制作方法,如下<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; build/make/target/product/security/README</span><br><span class="line"></span><br><span class="line">key generation</span><br><span class="line">--------------</span><br><span class="line"></span><br><span class="line">The following commands were used to generate the test key pairs:</span><br><span class="line"></span><br><span class="line"> development/tools/make_key testkey &apos;/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/[email protected]&apos;</span><br><span class="line"> development/tools/make_key platform &apos;/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/[email protected]&apos;</span><br><span class="line"> development/tools/make_key shared &apos;/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/[email protected]&apos;</span><br><span class="line"> development/tools/make_key media &apos;/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/[email protected]&apos;</span><br></pre></td></tr></table></figure></p>
<p>通过development/tools/make_key生成对应信息的key,参数的定义如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">C ---&gt; Country Name (2 letter code)</span><br><span class="line">ST ---&gt; State or Province Name (full name)</span><br><span class="line">L ---&gt; Locality Name (eg, city)</span><br><span class="line">O ---&gt; Organization Name (eg, company)</span><br><span class="line">OU ---&gt; Organizational Unit Name (eg, section)</span><br><span class="line">CN ---&gt; Common Name (eg, your name or your server’s hostname)</span><br><span class="line">emailAddress ---&gt; Contact email address</span><br></pre></td></tr></table></figure></p>
<p>可在源码根目录下运行如下脚本统一制作:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/bash</span><br><span class="line"></span><br><span class="line">subject=&apos;/C=CN/ST=Guangdong/L=Shenzhen View/O=Android/OU=Android/CN=Android/[email protected]&apos;</span><br><span class="line">mkdir ~/.android-certs</span><br><span class="line">for x in releasekey platform shared media verity; do \</span><br><span class="line"> ./development/tools/make_key ~/.android-certs/$x &quot;$subject&quot;; \</span><br><span class="line">done</span><br></pre></td></tr></table></figure></p>
<h2 id="为DM-Verity功能生成verity-key"><a href="#为DM-Verity功能生成verity-key" class="headerlink" title="为DM-Verity功能生成verity key"></a>为DM-Verity功能生成verity key</h2><p>首先通过使用以下的命令来生成verity key的工具generate_verity_key:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">source build/envsetup.sh</span><br><span class="line">choosecombo</span><br><span class="line">make generate_verity_key (mmm system/extras/verity/)</span><br></pre></td></tr></table></figure></p>
<p>然后在前面步骤已生成verity.pk8,verity.x509.pem的基础上使用以下命令生成verity_key<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">out/host/linux-x86/bin/generate_verity_key -convert verity.x509.pem verity_key</span><br></pre></td></tr></table></figure></p>
<h1 id="APK签名"><a href="#APK签名" class="headerlink" title="APK签名"></a>APK签名</h1><ol>
<li>keystore签名<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># jarsigner -verbose -keystore debug.keystore -signedjar signed.apk unsign.apk androiddebugkey</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>签名的时候报如下的问题,说明待签的apk是已经签名过的:<br>jarsigner: 无法对 jar 进行签名: java.util.zip.ZipException: invalid entry compressed size (expected 5067 but got 5217 bytes)<br>解决的方法:<br>把要重签名的apk后缀改成zip,打开后删除里面的META-INF目录,然后重新改成apk后缀再进行签名操作</p>
<ol>
<li>秘钥签名<br>java -Xmx512m -jar signapk.jar xxx.x509.pem xxx.pk8 release.apk release_signed.apk</li>
</ol>
</content>
<summary type="html">
<blockquote>
<p>Android OS 镜像在两个地方使用加密签名:</p>
<ol>
<li>映像中的所有.apk文件都必须经过签名。Android软件包管理器通过下列两种方式使用.apk 签名:<ul>
<li>更换应用时,必须使用与旧应用相同的密钥对其签名,才
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Build" scheme="http://robinheztto.com/tags/Build/"/>
<category term="Sign" scheme="http://robinheztto.com/tags/Sign/"/>
</entry>
<entry>
<title>Android持续集成之Jenkins</title>
<link href="http://robinheztto.com/2018/05/03/android-ci-jenkins/"/>
<id>http://robinheztto.com/2018/05/03/android-ci-jenkins/</id>
<published>2018-05-03T07:17:21.000Z</published>
<updated>2018-06-24T16:24:25.000Z</updated>
<content type="html"><blockquote>
<p>Jenkins是一个独立的开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。前身是Hudson是一个可扩展的持续集成引擎。可用于自动化各种任务,如构建,测试和部署软件。</p>
</blockquote>
<h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -</span><br><span class="line">$ sudo sh -c &apos;echo deb http://pkg.jenkins-ci.org/debian binary/ &gt; /etc/apt/sources.list.d/jenkins.list&apos;</span><br><span class="line">$ sudo apt-get update -y</span><br><span class="line">$ sudo apt-get install jenkins -y</span><br><span class="line">$ sudo /etc/init.d/jenkins start</span><br></pre></td></tr></table></figure>
<p>完成以上步骤后,通过浏览器打开 <a href="http://localhost:8080," target="_blank" rel="external">http://localhost:8080,</a> 如果无法启动jenkins,可在/var/log/jenkins/jenkins.log下查看Jenkins log</p>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/ci/jenkins-error-log.png?raw=true" alt="jenkins-error-log"><br></div>
<p>如上图示,出现上面的报错信息,即端口号被占用,需按以下步骤修改Jenkins端口号</p>
<p>1.修改/etc/init.d/jenkins中do_start函数check_tcp_port命令,将端口号从8080换成8081</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">$ sudo vi /etc/init.d/jenkins</span><br><span class="line"></span><br><span class="line">#</span><br><span class="line"># Function that starts the daemon/service</span><br><span class="line">#</span><br><span class="line">do_start()</span><br><span class="line">&#123;</span><br><span class="line"> ......</span><br><span class="line"></span><br><span class="line"> # Verify that the jenkins port is not already in use, winstone does not exit</span><br><span class="line"> # even for BindException</span><br><span class="line"> check_tcp_port &quot;http&quot; &quot;$HTTP_PORT&quot; &quot;8081&quot; &quot;$HTTP_HOST&quot; &quot;0.0.0.0&quot; || return 2</span><br><span class="line"></span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>2.修改/etc/default/jenkins文件,将端口8080改成8081<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ sudo vi /etc/default/jenkins</span><br><span class="line"></span><br><span class="line"># port for HTTP connector (default 8080; disable with -1)</span><br><span class="line">HTTP_PORT=8081</span><br></pre></td></tr></table></figure></p>
<p>3.重新启动jenkins<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ sudo /etc/init.d/jenkins start</span><br><span class="line">$ ps -ef | grep jenkins</span><br></pre></td></tr></table></figure></p>
<h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>浏览器打开gerrit url,即出现如下界面,admin初始密码保存在/var/lib/jenkins/secrets</p>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/ci/jenkins-login.png?raw=true" alt="jenkins-login"><br></div>
<p>首次进入账户,根据提示安装推介的插件</p>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/ci/jenkins-startup.png?raw=true" alt="jenkins-startup"><br></div>
<p>推介安装包括如下插件</p>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/ci/jenkins-startup-1.png?raw=true" alt="jenkins-startup-1"><br></div>
<p>进入jenkins后,界面如下显示</p>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/ci/jenkins-page.png?raw=true" alt="jenkins-page"><br></div>
</content>
<summary type="html">
<blockquote>
<p>Jenkins是一个独立的开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。前身是Hudson是一个可扩展的持续集成引擎。可用于自动化各种任务,如构建,测试和部署软
</summary>
<category term="CI" scheme="http://robinheztto.com/tags/CI/"/>
<category term="jenkins" scheme="http://robinheztto.com/tags/jenkins/"/>
</entry>
<entry>
<title>Android电源管理系列之Deep Doze</title>
<link href="http://robinheztto.com/2017/09/15/android-power-doze-deep/"/>
<id>http://robinheztto.com/2017/09/15/android-power-doze-deep/</id>
<published>2017-09-15T02:36:15.000Z</published>
<updated>2018-06-24T16:24:25.000Z</updated>
<content type="html"><h1 id="STATE-ACTIVE-gt-STATE-INACTIVE"><a href="#STATE-ACTIVE-gt-STATE-INACTIVE" class="headerlink" title="STATE_ACTIVE -&gt; STATE_INACTIVE"></a>STATE_ACTIVE -&gt; STATE_INACTIVE</h1><p>如上文所述,当Screen off或者unplug事件触发时,进入becomeInactiveIfAppropriateLocked执行。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">void becomeInactiveIfAppropriateLocked() &#123;</span><br><span class="line"> // 灭屏且未充电 </span><br><span class="line"> if ((!mScreenOn &amp;&amp; !mCharging) || mForceIdle) &#123;</span><br><span class="line"> // 进入deep模式状态机轮转</span><br><span class="line"> if (mState == STATE_ACTIVE &amp;&amp; mDeepEnabled) &#123;</span><br><span class="line"> // 切换到STATE_INACTIVE状态</span><br><span class="line"> mState = STATE_INACTIVE;</span><br><span class="line"> // 重置状态值,定时器等</span><br><span class="line"> resetIdleManagementLocked();</span><br><span class="line"> // 启动Deep定时器,进入deep状态轮转</span><br><span class="line"> scheduleAlarmLocked(mInactiveTimeout, false);</span><br><span class="line"> EventLogTags.writeDeviceIdle(mState, &quot;no activity&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> // 当前模式是LIGHT_STATE_ACTIVE,且mLightEnabled开关打开(上篇博客已分析)</span><br><span class="line"> if (mLightState == LIGHT_STATE_ACTIVE &amp;&amp; mLightEnabled) &#123;</span><br><span class="line"> mLightState = LIGHT_STATE_INACTIVE;</span><br><span class="line"> resetLightIdleManagementLocked();</span><br><span class="line"> scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);</span><br><span class="line"> EventLogTags.writeDeviceIdleLight(mLightState, &quot;no activity&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>灭屏且未充电状态或mForceIdle状态满足时,STATE_ACTIVE切换到STATE_INACTIVE,并且启动定时器轮转状态机。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">// inactiveTimeoutDefaul默认值为30min</span><br><span class="line">long inactiveTimeoutDefault = (mHasWatch ? 15 : 30) * 60 * 1000L;</span><br><span class="line">INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,</span><br><span class="line"> !COMPRESS_TIME ? inactiveTimeoutDefault : (inactiveTimeoutDefault / 10));</span><br><span class="line"></span><br><span class="line">void scheduleAlarmLocked(long delay, boolean idleUntil) &#123;</span><br><span class="line"> if (mMotionSensor == null) &#123;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"> mNextAlarmTime = SystemClock.elapsedRealtime() + delay;</span><br><span class="line"> if (idleUntil) &#123;</span><br><span class="line"> mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,</span><br><span class="line"> mNextAlarmTime, &quot;DeviceIdleController.deep&quot;, mDeepAlarmListener, mHandler);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,</span><br><span class="line"> mNextAlarmTime, &quot;DeviceIdleController.deep&quot;, mDeepAlarmListener, mHandler);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>scheduleAlarmLocked调度定时器,时间mInactiveTimeout为Constants.INACTIVE_TIMEOUT,即inactive_to,默认为30min。</p>
<h1 id="STATE-INACTIVE-gt-STATE-IDLE-PENDING"><a href="#STATE-INACTIVE-gt-STATE-IDLE-PENDING" class="headerlink" title="STATE_INACTIVE -&gt; STATE_IDLE_PENDING"></a>STATE_INACTIVE -&gt; STATE_IDLE_PENDING</h1><p>在过mInactiveTimeout时间的定时后,进入mDeepAlarmListener中处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">private final AlarmManager.OnAlarmListener mDeepAlarmListener</span><br><span class="line"> = new AlarmManager.OnAlarmListener() &#123;</span><br><span class="line"> @Override</span><br><span class="line"> public void onAlarm() &#123;</span><br><span class="line"> synchronized (DeviceIdleController.this) &#123;</span><br><span class="line"> stepIdleStateLocked(&quot;s:alarm&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>继续看stepIdleStateLocked的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM,</span><br><span class="line"> !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);</span><br><span class="line"></span><br><span class="line">void stepIdleStateLocked(String reason) &#123;</span><br><span class="line"> final long now = SystemClock.elapsedRealtime();</span><br><span class="line"> // 如果60分钟内有可以从Deep Idle唤醒的定时器触发,暂时先退出状态机轮转</span><br><span class="line"> if ((now+mConstants.MIN_TIME_TO_ALARM) &gt; mAlarmManager.getNextWakeFromIdleTime()) &#123;</span><br><span class="line"> // 重置为STATE_ACTIVE状态</span><br><span class="line"> if (mState != STATE_ACTIVE) &#123;</span><br><span class="line"> becomeActiveLocked(&quot;alarm&quot;, Process.myUid());</span><br><span class="line"> becomeInactiveIfAppropriateLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> switch (mState) &#123;</span><br><span class="line"> case STATE_INACTIVE:</span><br><span class="line"> // 启动motion sensor监听</span><br><span class="line"> startMonitoringMotionLocked();</span><br><span class="line"> // 调度STATE_IDLE_PENDING状态的定时器,即idle_after_inactive_to,默认30min</span><br><span class="line"> scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);</span><br><span class="line"> // mNextIdlePendingDelay设置为idle_pending_to即5min</span><br><span class="line"> mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;</span><br><span class="line"> mNextIdleDelay = mConstants.IDLE_TIMEOUT;</span><br><span class="line"> // 切换状态为STATE_IDLE_PENDING</span><br><span class="line"> mState = STATE_IDLE_PENDING;</span><br><span class="line"> EventLogTags.writeDeviceIdle(mState, reason);</span><br><span class="line"> break;</span><br><span class="line"> case STATE_IDLE_PENDING:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case STATE_SENSING:</span><br><span class="line"> ......</span><br><span class="line"> case STATE_LOCATING:</span><br><span class="line"> ......</span><br><span class="line"> case STATE_IDLE_MAINTENANCE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case STATE_IDLE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>当进入STATE_IDLE_PENDING时,通过startMonitoringMotionLocked启动了motion sensor监听。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line">private final MotionListener mMotionListener = new MotionListener();</span><br><span class="line"></span><br><span class="line">void startMonitoringMotionLocked() &#123;</span><br><span class="line"> if (mMotionSensor != null &amp;&amp; !mMotionListener.active) &#123;</span><br><span class="line"> // 注册mMotionSensor监听</span><br><span class="line"> mMotionListener.registerLocked();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">private final class MotionListener extends TriggerEventListener</span><br><span class="line"> implements SensorEventListener &#123;</span><br><span class="line"></span><br><span class="line"> boolean active = false;</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public void onTrigger(TriggerEvent event) &#123;</span><br><span class="line"> synchronized (DeviceIdleController.this) &#123;</span><br><span class="line"> active = false;</span><br><span class="line"> // MotionSensor事件触发时,执行motionLocked</span><br><span class="line"> motionLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public void onSensorChanged(SensorEvent event) &#123;</span><br><span class="line"> synchronized (DeviceIdleController.this) &#123;</span><br><span class="line"> mSensorManager.unregisterListener(this, mMotionSensor);</span><br><span class="line"> active = false;</span><br><span class="line"> motionLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public void onAccuracyChanged(Sensor sensor, int accuracy) &#123;&#125;</span><br><span class="line"></span><br><span class="line"> // 注册MotionSensor监听</span><br><span class="line"> public boolean registerLocked() &#123;</span><br><span class="line"> boolean success;</span><br><span class="line"> if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) &#123;</span><br><span class="line"> success = mSensorManager.requestTriggerSensor(mMotionListener, mMotionSensor);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> success = mSensorManager.registerListener(</span><br><span class="line"> mMotionListener, mMotionSensor, SensorManager.SENSOR_DELAY_NORMAL);</span><br><span class="line"> &#125;</span><br><span class="line"> if (success) &#123;</span><br><span class="line"> active = true;</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> Slog.e(TAG, &quot;Unable to register for &quot; + mMotionSensor);</span><br><span class="line"> &#125;</span><br><span class="line"> return success;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> public void unregisterLocked() &#123;</span><br><span class="line"> if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) &#123;</span><br><span class="line"> mSensorManager.cancelTriggerSensor(mMotionListener, mMotionSensor);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> mSensorManager.unregisterListener(mMotionListener);</span><br><span class="line"> &#125;</span><br><span class="line"> active = false;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>当mMotionSensor事件触发时,motionLocked被调动执行。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">void motionLocked() &#123;</span><br><span class="line"> handleMotionDetectedLocked(mConstants.MOTION_INACTIVE_TIMEOUT, &quot;motion&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// handleMotionDetectedLocked中重置状态为STATE_ACTIVE,并重新设置mInactiveTimeout为</span><br><span class="line">// mConstants.MOTION_INACTIVE_TIMEOUT,即motion_inactive_to,默认是10分钟</span><br><span class="line">// 即如果由于MotionSensor检测到的动作而退出了INACTIVE状态,再次从INACTIVE切换</span><br><span class="line">// 到IDLE_PENDING的时间就从原先的30分钟缩短到了10分钟。</span><br><span class="line">void handleMotionDetectedLocked(long timeout, String type) &#123;</span><br><span class="line"> boolean becomeInactive = false;</span><br><span class="line"> if (mState != STATE_ACTIVE) &#123;</span><br><span class="line"> scheduleReportActiveLocked(type, Process.myUid());</span><br><span class="line"> mState = STATE_ACTIVE;</span><br><span class="line"> mInactiveTimeout = timeout;</span><br><span class="line"> mCurIdleBudget = 0;</span><br><span class="line"> mMaintenanceStartTime = 0;</span><br><span class="line"> EventLogTags.writeDeviceIdle(mState, type);</span><br><span class="line"> addEvent(EVENT_NORMAL);</span><br><span class="line"> becomeInactive = true;</span><br><span class="line"> &#125;</span><br><span class="line"> if (mLightState == LIGHT_STATE_OVERRIDE) &#123;</span><br><span class="line"> // We went out of light idle mode because we had started deep idle mode... let&apos;s</span><br><span class="line"> // now go back and reset things so we resume light idling if appropriate.</span><br><span class="line"> mLightState = STATE_ACTIVE;</span><br><span class="line"> EventLogTags.writeDeviceIdleLight(mLightState, type);</span><br><span class="line"> becomeInactive = true;</span><br><span class="line"> &#125;</span><br><span class="line"> if (becomeInactive) &#123;</span><br><span class="line"> becomeInactiveIfAppropriateLocked();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="STATE-IDLE-PENDING-gt-STATE-SENSING"><a href="#STATE-IDLE-PENDING-gt-STATE-SENSING" class="headerlink" title="STATE_IDLE_PENDING -&gt; STATE_SENSING"></a>STATE_IDLE_PENDING -&gt; STATE_SENSING</h1><p>当STATE_IDLE_PENDING定时时间到后,继续进入到stepIdleStateLocked中处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">void stepIdleStateLocked(String reason) &#123;</span><br><span class="line"> ......</span><br><span class="line"> switch (mState) &#123;</span><br><span class="line"> case STATE_INACTIVE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case STATE_IDLE_PENDING:</span><br><span class="line"> // 切换状态到STATE_SENSING</span><br><span class="line"> mState = STATE_SENSING;</span><br><span class="line"> EventLogTags.writeDeviceIdle(mState, reason);</span><br><span class="line"> // 调度STATE_SENSING状态定时器,SENSING_TIMEOUT即sensing_to,默认4min,正常情况下该定时器不会被触发</span><br><span class="line"> scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);</span><br><span class="line"> cancelLocatingLocked();</span><br><span class="line"> mNotMoving = false;</span><br><span class="line"> mLocated = false;</span><br><span class="line"> mLastGenericLocation = null;</span><br><span class="line"> mLastGpsLocation = null;</span><br><span class="line"> // 启动AnyMotionDetector,利用加速度传感器监测是否有方向的变化</span><br><span class="line"> mAnyMotionDetector.checkForAnyMotion();</span><br><span class="line"> break;</span><br><span class="line"> case STATE_SENSING:</span><br><span class="line"> ......</span><br><span class="line"> case STATE_LOCATING:</span><br><span class="line"> ......</span><br><span class="line"> case STATE_IDLE_MAINTENANCE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case STATE_IDLE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>stepIdleStateLocked对STATE_SENSING的处理同样是启动一个定时器,但是该定时器不会被触发,也就是STATE_SENSING状态的轮转不依靠定时器进行,而是在mAnyMotionDetector的监测结果的回调onAnyMotionResult()中进行。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">public void onAnyMotionResult(int result) &#123;</span><br><span class="line"> if (result != AnyMotionDetector.RESULT_UNKNOWN) &#123;</span><br><span class="line"> synchronized (this) &#123;</span><br><span class="line"> // 取消STATE_SENSING的定时器</span><br><span class="line"> cancelSensingTimeoutAlarmLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> if ((result == AnyMotionDetector.RESULT_MOVED) ||</span><br><span class="line"> (result == AnyMotionDetector.RESULT_UNKNOWN)) &#123;</span><br><span class="line"> synchronized (this) &#123;</span><br><span class="line"> handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, &quot;non_stationary&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; else if (result == AnyMotionDetector.RESULT_STATIONARY) &#123;</span><br><span class="line"> if (mState == STATE_SENSING) &#123;</span><br><span class="line"> // If we are currently sensing, it is time to move to locating.</span><br><span class="line"> synchronized (this) &#123;</span><br><span class="line"> mNotMoving = true;</span><br><span class="line"> stepIdleStateLocked(&quot;s:stationary&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; else if (mState == STATE_LOCATING) &#123;</span><br><span class="line"> // If we are currently locating, note that we are not moving and step</span><br><span class="line"> // if we have located the position.</span><br><span class="line"> synchronized (this) &#123;</span><br><span class="line"> mNotMoving = true;</span><br><span class="line"> if (mLocated) &#123;</span><br><span class="line"> stepIdleStateLocked(&quot;s:stationary&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>当检测结果为MOVED时,调用handleMotionDetectedLocked重置状态为ACTIVE,如果结果为RESULT_STATIONARY,当前状态为SENSING时,调用stopIdleStateLocked轮转到下一个状态,也就是进入到LOCATING状态,那么如果当前为LOCATING时,需要另外对mLocated变量进行判断才决定是否进行下一次切换。</p>
<h1 id="STATE-SENSING-gt-STATE-LOCATING"><a href="#STATE-SENSING-gt-STATE-LOCATING" class="headerlink" title="STATE_SENSING -&gt; STATE_LOCATING"></a>STATE_SENSING -&gt; STATE_LOCATING</h1><p>stepIdleStateLocked对STATE_LOCATING状态的处理同样是启动一个定时器,并通过LocationManager请求对位置的监听。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">void stepIdleStateLocked(String reason) &#123;</span><br><span class="line"> ......</span><br><span class="line"> switch (mState) &#123;</span><br><span class="line"> case STATE_INACTIVE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case STATE_IDLE_PENDING:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case STATE_SENSING:</span><br><span class="line"> cancelSensingTimeoutAlarmLocked();</span><br><span class="line"> mState = STATE_LOCATING;</span><br><span class="line"> EventLogTags.writeDeviceIdle(mState, reason);</span><br><span class="line"> // 调度STATE_LOCATING状态定时器,LOCATING_TIMEOUT即locating_to,默认30s</span><br><span class="line"> scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);</span><br><span class="line"> // 通过LocationManager请求位置监听</span><br><span class="line"> if (mLocationManager != null</span><br><span class="line"> &amp;&amp; mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) &#123;</span><br><span class="line"> mLocationManager.requestLocationUpdates(mLocationRequest,</span><br><span class="line"> mGenericLocationListener, mHandler.getLooper());</span><br><span class="line"> mLocating = true;</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> mHasNetworkLocation = false;</span><br><span class="line"> &#125;</span><br><span class="line"> if (mLocationManager != null</span><br><span class="line"> &amp;&amp; mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) &#123;</span><br><span class="line"> mHasGps = true;</span><br><span class="line"> mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,</span><br><span class="line"> mGpsLocationListener, mHandler.getLooper());</span><br><span class="line"> mLocating = true;</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> mHasGps = false;</span><br><span class="line"> &#125;</span><br><span class="line"> // 如果没有location provider,将通过listeners回调轮状状态</span><br><span class="line"> if (mLocating) &#123;</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line"> case STATE_LOCATING:</span><br><span class="line"> ......</span><br><span class="line"> case STATE_IDLE_MAINTENANCE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case STATE_IDLE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>STATE_LOCATING的状态在mGenericLocationListener/mGpsLocationListener中进行轮转。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">private final LocationListener mGenericLocationListener = new LocationListener() &#123;</span><br><span class="line"> @Override</span><br><span class="line"> public void onLocationChanged(Location location) &#123;</span><br><span class="line"> synchronized (DeviceIdleController.this) &#123;</span><br><span class="line"> receivedGenericLocationLocked(location);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> ......</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">private final LocationListener mGpsLocationListener = new LocationListener() &#123;</span><br><span class="line"> @Override</span><br><span class="line"> public void onLocationChanged(Location location) &#123;</span><br><span class="line"> synchronized (DeviceIdleController.this) &#123;</span><br><span class="line"> receivedGpsLocationLocked(location);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> ......</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void receivedGenericLocationLocked(Location location) &#123;</span><br><span class="line"> if (mState != STATE_LOCATING) &#123;</span><br><span class="line"> cancelLocatingLocked();</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"> if (DEBUG) Slog.d(TAG, &quot;Generic location: &quot; + location);</span><br><span class="line"> mLastGenericLocation = new Location(location);</span><br><span class="line"> if (location.getAccuracy() &gt; mConstants.LOCATION_ACCURACY &amp;&amp; mHasGps) &#123;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"> mLocated = true;</span><br><span class="line"> if (mNotMoving) &#123;</span><br><span class="line"> stepIdleStateLocked(&quot;s:location&quot;);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void receivedGpsLocationLocked(Location location) &#123;</span><br><span class="line"> if (mState != STATE_LOCATING) &#123;</span><br><span class="line"> cancelLocatingLocked();</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"> if (DEBUG) Slog.d(TAG, &quot;GPS location: &quot; + location);</span><br><span class="line"> mLastGpsLocation = new Location(location);</span><br><span class="line"> if (location.getAccuracy() &gt; mConstants.LOCATION_ACCURACY) &#123;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"> mLocated = true;</span><br><span class="line"> if (mNotMoving) &#123;</span><br><span class="line"> stepIdleStateLocked(&quot;s:gps&quot;);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>如果开启了Gps的定位监测,并且精度大于LOCATION_ACCURACY,那么这里的监测就忽略,如果监测数据为Not move,那么就调用StepIdleStateLocked来进行下一步。</p>
<h1 id="STATE-LOCATING-gt-STATE-IDLE"><a href="#STATE-LOCATING-gt-STATE-IDLE" class="headerlink" title="STATE_LOCATING -&gt; STATE_IDLE"></a>STATE_LOCATING -&gt; STATE_IDLE</h1><h1 id="STATE-IDLE-MAINTENANCE-gt-STATE-IDLE"><a href="#STATE-IDLE-MAINTENANCE-gt-STATE-IDLE" class="headerlink" title="STATE_IDLE_MAINTENANCE -&gt; STATE_IDLE"></a>STATE_IDLE_MAINTENANCE -&gt; STATE_IDLE</h1><h1 id="STATE-LOCATING-gt-STATE-IDLE-MAINTENANCE"><a href="#STATE-LOCATING-gt-STATE-IDLE-MAINTENANCE" class="headerlink" title="STATE_LOCATING -&gt; STATE_IDLE_MAINTENANCE"></a>STATE_LOCATING -&gt; STATE_IDLE_MAINTENANCE</h1></content>
<summary type="html">
<h1 id="STATE-ACTIVE-gt-STATE-INACTIVE"><a href="#STATE-ACTIVE-gt-STATE-INACTIVE" class="headerlink" title="STATE_ACTIVE -&gt; STATE_INACTIV
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power Management" scheme="http://robinheztto.com/tags/Power-Management/"/>
<category term="Doze" scheme="http://robinheztto.com/tags/Doze/"/>
</entry>
<entry>
<title>Android电源管理系列之Light Doze</title>
<link href="http://robinheztto.com/2017/09/13/android-power-doze-light/"/>
<id>http://robinheztto.com/2017/09/13/android-power-doze-light/</id>
<published>2017-09-13T02:36:15.000Z</published>
<updated>2018-06-24T16:24:25.000Z</updated>
<content type="html"><p>Light Doze的状态切换如下图示:</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/light_doze.png?raw=true" alt="light doze machine state"><br></div></p>
<h2 id="LIGHT-STATE-ACTIVE-gt-LIGHT-STATE-INACTIVE"><a href="#LIGHT-STATE-ACTIVE-gt-LIGHT-STATE-INACTIVE" class="headerlink" title="LIGHT_STATE_ACTIVE -&gt; LIGHT_STATE_INACTIVE"></a>LIGHT_STATE_ACTIVE -&gt; LIGHT_STATE_INACTIVE</h2><p>DeviceIdleController服务启动过程中注册了DisplayListener,BATTERY_CHANGED Receiver监听屏幕亮灭与充电状态事件。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">void updateDisplayLocked() &#123;</span><br><span class="line"> // 获取default Display </span><br><span class="line"> mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);</span><br><span class="line"> boolean screenOn = mCurDisplay.getState() == Display.STATE_ON;</span><br><span class="line"> // 灭屏</span><br><span class="line"> if (!screenOn &amp;&amp; mScreenOn) &#123;</span><br><span class="line"> mScreenOn = false;</span><br><span class="line"> if (!mForceIdle) &#123;</span><br><span class="line"> becomeInactiveIfAppropriateLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> // 亮屏</span><br><span class="line"> &#125; else if (screenOn) &#123;</span><br><span class="line"> mScreenOn = true;</span><br><span class="line"> if (!mForceIdle) &#123;</span><br><span class="line"> becomeActiveLocked(&quot;screen&quot;, Process.myUid());</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void updateChargingLocked(boolean charging) &#123;</span><br><span class="line"> // 未充电状态</span><br><span class="line"> if (!charging &amp;&amp; mCharging) &#123;</span><br><span class="line"> mCharging = false;</span><br><span class="line"> if (!mForceIdle) &#123;</span><br><span class="line"> becomeInactiveIfAppropriateLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> // 充电状态</span><br><span class="line"> &#125; else if (charging) &#123;</span><br><span class="line"> mCharging = charging;</span><br><span class="line"> if (!mForceIdle) &#123;</span><br><span class="line"> becomeActiveLocked(&quot;charging&quot;, Process.myUid());</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>当灭屏或未充电状态事件触发时,调用becomeInactiveIfAppropriateLocked进行状态处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">void becomeInactiveIfAppropriateLocked() &#123;</span><br><span class="line"> // 灭屏且未充电 </span><br><span class="line"> if ((!mScreenOn &amp;&amp; !mCharging) || mForceIdle) &#123;</span><br><span class="line"> // 进入deep模式,在下篇博客中分析</span><br><span class="line"> if (mState == STATE_ACTIVE &amp;&amp; mDeepEnabled) &#123;</span><br><span class="line"> mState = STATE_INACTIVE;</span><br><span class="line"> resetIdleManagementLocked();</span><br><span class="line"> scheduleAlarmLocked(mInactiveTimeout, false);</span><br><span class="line"> EventLogTags.writeDeviceIdle(mState, &quot;no activity&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> // 当前模式是LIGHT_STATE_ACTIVE,且mLightEnabled开关打开(上篇博客已分析)</span><br><span class="line"> if (mLightState == LIGHT_STATE_ACTIVE &amp;&amp; mLightEnabled) &#123;</span><br><span class="line"> // 切换当前light状态为LIGHT_STATE_INACTIVE</span><br><span class="line"> mLightState = LIGHT_STATE_INACTIVE;</span><br><span class="line"> // 取消Light定时器</span><br><span class="line"> resetLightIdleManagementLocked();</span><br><span class="line"> // 启动Light定时器,进入Light状态机轮转</span><br><span class="line"> scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);</span><br><span class="line"> EventLogTags.writeDeviceIdleLight(mLightState, &quot;no activity&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void scheduleLightAlarmLocked(long delay) &#123;</span><br><span class="line"> mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;</span><br><span class="line"> // 定时时间到后,mLightAlarmListener将在mHandler关联的BackgroundThread线程中执行</span><br><span class="line"> mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,</span><br><span class="line"> mNextLightAlarmTime, &quot;DeviceIdleController.light&quot;, mLightAlarmListener, mHandler);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>灭屏且未充电状态或打开强制Idle状态满足时,LIGHT_STATE_ACTIVE切换到LIGHT_STATE_INACTIVE,并且启动定时器轮转状态机。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(</span><br><span class="line"> KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,</span><br><span class="line"> !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);</span><br></pre></td></tr></table></figure></p>
<p>定时器定时时间LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT即light_idle_to默认为5min。</p>
<h2 id="LIGHT-STATE-INACTIVE-gt-LIGHT-STATE-PRE-IDLE"><a href="#LIGHT-STATE-INACTIVE-gt-LIGHT-STATE-PRE-IDLE" class="headerlink" title="LIGHT_STATE_INACTIVE -&gt; LIGHT_STATE_PRE_IDLE"></a>LIGHT_STATE_INACTIVE -&gt; LIGHT_STATE_PRE_IDLE</h2><p>在过LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT时间的定时后,进入mLightAlarmListener中处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">private final AlarmManager.OnAlarmListener mLightAlarmListener</span><br><span class="line"> = new AlarmManager.OnAlarmListener() &#123;</span><br><span class="line"> @Override</span><br><span class="line"> public void onAlarm() &#123;</span><br><span class="line"> synchronized (DeviceIdleController.this) &#123;</span><br><span class="line"> stepLightIdleStateLocked(&quot;s:alarm&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>继续看stepLightIdleStateLocked的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">// LIGHT_STATE_IDLE_MAINTENANCE最短时间,默认为1min</span><br><span class="line">LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mParser.getLong(</span><br><span class="line"> KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,</span><br><span class="line"> !COMPRESS_TIME ? 1 * 60 * 1000L : 15 * 1000L);</span><br><span class="line"></span><br><span class="line">// LIGHT_IDLE_TIMEOUT默认值为5min</span><br><span class="line">LIGHT_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_IDLE_TIMEOUT,</span><br><span class="line"> !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L); </span><br><span class="line"></span><br><span class="line">// LIGHT_STATE_PRE_IDLE时间,默认为10min</span><br><span class="line">LIGHT_PRE_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_PRE_IDLE_TIMEOUT,</span><br><span class="line"> !COMPRESS_TIME ? 10 * 60 * 1000L : 30 * 1000L); </span><br><span class="line"></span><br><span class="line">void stepLightIdleStateLocked(String reason) &#123;</span><br><span class="line"> // 如果处于Deep mode的IDLE状态,Light Mode将会被忽略</span><br><span class="line"> if (mLightState == LIGHT_STATE_OVERRIDE) &#123;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 当前mLightState处于LIGHT_STATE_INACTIVE状态</span><br><span class="line"> switch (mLightState) &#123;</span><br><span class="line"> case LIGHT_STATE_INACTIVE:</span><br><span class="line"> // LIGHT_STATE_IDLE_MAINTENANCE最短时间,默认为1min</span><br><span class="line"> mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;</span><br><span class="line"> // Idle时间初始值为LIGHT_IDLE_TIMEOUT,5min</span><br><span class="line"> mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;</span><br><span class="line"> mMaintenanceStartTime = 0;</span><br><span class="line"> // 当前有Alarm或job等active ops,先进入LIGHT_STATE_PRE_IDLE状态等待完成,否则直接进入LIGHT_STATE_PRE_IDLE</span><br><span class="line"> if (!isOpsInactiveLocked()) &#123;</span><br><span class="line"> mLightState = LIGHT_STATE_PRE_IDLE;</span><br><span class="line"> EventLogTags.writeDeviceIdleLight(mLightState, reason);</span><br><span class="line"> // 设置LIGHT_STATE_PRE_IDLE时间,默认为10min</span><br><span class="line"> scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line"> case LIGHT_STATE_PRE_IDLE:</span><br><span class="line"> case LIGHT_STATE_IDLE_MAINTENANCE:</span><br><span class="line"> .......</span><br><span class="line"> break;</span><br><span class="line"> case LIGHT_STATE_IDLE:</span><br><span class="line"> case LIGHT_STATE_WAITING_FOR_NETWORK:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>stepLightIdleStateLocked中LIGHT_STATE_INACTIVE的处理,当首次进入存在active ops时,将会进入LIGHT_STATE_PRE_IDLE状态,等待当前处理完成,mConstants.LIGHT_PRE_IDLE_TIMEOUT即light_pre_idle_to时间到后,再次进入stepLightIdleStateLocked中进行处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">boolean isOpsInactiveLocked() &#123;</span><br><span class="line"> return mActiveIdleOpCount &lt;= 0 &amp;&amp; !mJobsActive &amp;&amp; !mAlarmsActive;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="LIGHT-STATE-PRE-IDLE-gt-LIGHT-STATE-IDLE"><a href="#LIGHT-STATE-PRE-IDLE-gt-LIGHT-STATE-IDLE" class="headerlink" title="LIGHT_STATE_PRE_IDLE -&gt; LIGHT_STATE_IDLE"></a>LIGHT_STATE_PRE_IDLE -&gt; LIGHT_STATE_IDLE</h2><p>当LIGHT_STATE_PRE_IDLE定时时间到后,继续进入到stepLightIdleStateLocked中处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">void stepLightIdleStateLocked(String reason) &#123;</span><br><span class="line"> if (mLightState == LIGHT_STATE_OVERRIDE) &#123;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 当前mLightState处于LIGHT_STATE_PRE_IDLE状态</span><br><span class="line"> switch (mLightState) &#123;</span><br><span class="line"> case LIGHT_STATE_INACTIVE:</span><br><span class="line"> ......</span><br><span class="line"> case LIGHT_STATE_PRE_IDLE:</span><br><span class="line"> case LIGHT_STATE_IDLE_MAINTENANCE:</span><br><span class="line"> // 当前mMaintenanceStartTime=0</span><br><span class="line"> if (mMaintenanceStartTime != 0) &#123;</span><br><span class="line"> long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;</span><br><span class="line"> if (duration &lt; mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) &#123;</span><br><span class="line"> // We didn&apos;t use up all of our minimum budget; add this to the reserve.</span><br><span class="line"> mCurIdleBudget += (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET-duration);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> // We used more than our minimum budget; this comes out of the reserve.</span><br><span class="line"> mCurIdleBudget -= (duration-mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> mMaintenanceStartTime = 0;</span><br><span class="line"> // 设置IDLE时间,初始值为LIGHT_IDLE_TIMEOUT,5min</span><br><span class="line"> scheduleLightAlarmLocked(mNextLightIdleDelay);</span><br><span class="line"> // 设置下次IDLE的时间,5*2^min</span><br><span class="line"> // 最长LIGHT_MAX_IDLE_TIMEOUT,15min,最短LIGHT_IDLE_TIMEOUT,5min</span><br><span class="line"> mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,</span><br><span class="line"> (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));</span><br><span class="line"> if (mNextLightIdleDelay &lt; mConstants.LIGHT_IDLE_TIMEOUT) &#123;</span><br><span class="line"> mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;</span><br><span class="line"> &#125;</span><br><span class="line"> if (DEBUG) Slog.d(TAG, &quot;Moved to LIGHT_STATE_IDLE.&quot;);</span><br><span class="line"> // 进入LIGHT_STATE_IDLE模式</span><br><span class="line"> mLightState = LIGHT_STATE_IDLE;</span><br><span class="line"> EventLogTags.writeDeviceIdleLight(mLightState, reason);</span><br><span class="line"> addEvent(EVENT_LIGHT_IDLE);</span><br><span class="line"> // 发送消息,进行LIGHT_STATE_IDLE状态相关的处理</span><br><span class="line"> mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);</span><br><span class="line"> break;</span><br><span class="line"> case LIGHT_STATE_IDLE:</span><br><span class="line"> case LIGHT_STATE_WAITING_FOR_NETWORK:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>stepLightIdleStateLocked中对LIGHT_STATE_PRE_IDLE状态的处理,进入LIGHT_STATE_IDLE状态并设置时间,然后发送消息进行状态切换相关的处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line">final class MyHandler extends Handler &#123;</span><br><span class="line"> ......</span><br><span class="line"> @Override public void handleMessage(Message msg) &#123;</span><br><span class="line"> if (DEBUG) Slog.d(TAG, &quot;handleMessage(&quot; + msg.what + &quot;)&quot;);</span><br><span class="line"> switch (msg.what) &#123;</span><br><span class="line"> case MSG_WRITE_CONFIG: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_REPORT_IDLE_ON:</span><br><span class="line"> case MSG_REPORT_IDLE_ON_LIGHT: &#123;</span><br><span class="line"> final boolean deepChanged;</span><br><span class="line"> final boolean lightChanged;</span><br><span class="line"> if (msg.what == MSG_REPORT_IDLE_ON) &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> // LocalPowerManager设置LightDeviceIdle模式</span><br><span class="line"> deepChanged = mLocalPowerManager.setDeviceIdleMode(false);</span><br><span class="line"> lightChanged = mLocalPowerManager.setLightDeviceIdleMode(true);</span><br><span class="line"> &#125;</span><br><span class="line"> try &#123;</span><br><span class="line"> // NetworkPolicyManager设置DeviceIdle模式,禁止非白名单应用联网</span><br><span class="line"> mNetworkPolicyManager.setDeviceIdleMode(true);</span><br><span class="line"> mBatteryStats.noteDeviceIdleMode(msg.what == MSG_REPORT_IDLE_ON</span><br><span class="line"> ? BatteryStats.DEVICE_IDLE_MODE_DEEP</span><br><span class="line"> : BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());</span><br><span class="line"> &#125; catch (RemoteException e) &#123;</span><br><span class="line"> &#125;</span><br><span class="line"> ......</span><br><span class="line"> // 发送LightIdle模式切换广播</span><br><span class="line"> if (lightChanged) &#123;</span><br><span class="line"> getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);</span><br><span class="line"> &#125;</span><br><span class="line"> EventLogTags.writeDeviceIdleOnComplete();</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_REPORT_IDLE_OFF: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_REPORT_ACTIVE: &#123;</span><br><span class="line"> ...... </span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_TEMP_APP_WHITELIST_TIMEOUT: &#123;</span><br><span class="line"> ...... </span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_REPORT_MAINTENANCE_ACTIVITY: &#123;</span><br><span class="line"> ...... </span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_FINISH_IDLE_OP: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>在MyHandler中会对MSG_REPORT_IDLE_ON_LIGHT消息进行一系列的处理通知各个模块对LightDeviceId进行处理,包括禁止网络,推迟SyncManager,jobsheduler等。</p>
<h2 id="LIGHT-STATE-IDLE-gt-LIGHT-STATE-IDLE-MAINTENANCE"><a href="#LIGHT-STATE-IDLE-gt-LIGHT-STATE-IDLE-MAINTENANCE" class="headerlink" title="LIGHT_STATE_IDLE -&gt; LIGHT_STATE_IDLE_MAINTENANCE"></a>LIGHT_STATE_IDLE -&gt; LIGHT_STATE_IDLE_MAINTENANCE</h2><h2 id="LIGHT-STATE-IDLE-gt-LIGHT-STATE-WAITING-FOR-NETWORK"><a href="#LIGHT-STATE-IDLE-gt-LIGHT-STATE-WAITING-FOR-NETWORK" class="headerlink" title="LIGHT_STATE_IDLE -&gt; LIGHT_STATE_WAITING_FOR_NETWORK"></a>LIGHT_STATE_IDLE -&gt; LIGHT_STATE_WAITING_FOR_NETWORK</h2><p>当LIGHT_STATE_IDLE定时时间到后,继续进入到stepLightIdleStateLocked中进行处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line">LIGHT_IDLE_MAINTENANCE时间默认最短1min,最长5min</span><br><span class="line">LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mParser.getLong(</span><br><span class="line"> KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,</span><br><span class="line"> !COMPRESS_TIME ? 1 * 60 * 1000L : 15 * 1000L);</span><br><span class="line">LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mParser.getLong(</span><br><span class="line"> KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET,</span><br><span class="line"> !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);</span><br><span class="line"></span><br><span class="line">void stepLightIdleStateLocked(String reason) &#123;</span><br><span class="line"> ......</span><br><span class="line"> // 当前状态mLightState为LIGHT_STATE_IDLE</span><br><span class="line"> switch (mLightState) &#123;</span><br><span class="line"> case LIGHT_STATE_INACTIVE:</span><br><span class="line"> ......</span><br><span class="line"> case LIGHT_STATE_PRE_IDLE:</span><br><span class="line"> case LIGHT_STATE_IDLE_MAINTENANCE:</span><br><span class="line"> ......</span><br><span class="line"> break;</span><br><span class="line"> case LIGHT_STATE_IDLE:</span><br><span class="line"> case LIGHT_STATE_WAITING_FOR_NETWORK:</span><br><span class="line"> // 当前有网络连接时或为LIGHT_STATE_WAITING_FOR_NETWORK状态时,直接进入LIGHT_STATE_IDLE_MAINTENANCE状态</span><br><span class="line"> if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) &#123;</span><br><span class="line"> // 设置mActiveIdleOpCount初始值为1</span><br><span class="line"> mActiveIdleOpCount = 1;</span><br><span class="line"> // mActiveIdleWakeLock防止系统进入休眠</span><br><span class="line"> mActiveIdleWakeLock.acquire();</span><br><span class="line"> // mCurIdleBudget即mMaintenance windows时间最短1min最长5min</span><br><span class="line"> mMaintenanceStartTime = SystemClock.elapsedRealtime();</span><br><span class="line"> if (mCurIdleBudget &lt; mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) &#123;</span><br><span class="line"> mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;</span><br><span class="line"> &#125; else if (mCurIdleBudget &gt; mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) &#123;</span><br><span class="line"> mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;</span><br><span class="line"> &#125;</span><br><span class="line"> // 进入LIGHT_STATE_IDLE_MAINTENANCE状态并设置定时器</span><br><span class="line"> scheduleLightAlarmLocked(mCurIdleBudget);</span><br><span class="line"> if (DEBUG) Slog.d(TAG,</span><br><span class="line"> &quot;Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.&quot;);</span><br><span class="line"> mLightState = LIGHT_STATE_IDLE_MAINTENANCE;</span><br><span class="line"> EventLogTags.writeDeviceIdleLight(mLightState, reason);</span><br><span class="line"> addEvent(EVENT_LIGHT_MAINTENANCE);</span><br><span class="line"> // 发送消息,对LIGHT_STATE_IDLE_MAINTENANCE状态进行处理</span><br><span class="line"> mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> // 当前没有网络连接,先进入LIGHT_STATE_WAITING_FOR_NETWORK等待一个idle的周期</span><br><span class="line"> scheduleLightAlarmLocked(mNextLightIdleDelay);</span><br><span class="line"> if (DEBUG) Slog.d(TAG, &quot;Moved to LIGHT_WAITING_FOR_NETWORK.&quot;);</span><br><span class="line"> mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;</span><br><span class="line"> EventLogTags.writeDeviceIdleLight(mLightState, reason);</span><br><span class="line"> &#125;</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>当退出LIGHT_STATE_IDLE状态时,如当前有网络连接或者为LIGHT_STATE_WAITING_FOR_NETWORK状态,则直接进入LIGHT_STATE_IDLE_MAINTENANCE,并发送MSG_REPORT_IDLE_OFF消息处理该状态的切换。如当前没有网络连接时,则先进入LIGHT_STATE_WAITING_FOR_NETWORK等待一个idle的周期等待网络连接。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">final class MyHandler extends Handler &#123;</span><br><span class="line"> @Override public void handleMessage(Message msg) &#123;</span><br><span class="line"> if (DEBUG) Slog.d(TAG, &quot;handleMessage(&quot; + msg.what + &quot;)&quot;);</span><br><span class="line"> switch (msg.what) &#123;</span><br><span class="line"> case MSG_WRITE_CONFIG: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_REPORT_IDLE_ON:</span><br><span class="line"> case MSG_REPORT_IDLE_ON_LIGHT: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> // MSG_REPORT_IDLE_OFF即执行MSG_REPORT_IDLE_ON_LIGHT中的反操作,恢复LIGH_IDLE的限制操作</span><br><span class="line"> case MSG_REPORT_IDLE_OFF: &#123;</span><br><span class="line"> EventLogTags.writeDeviceIdleOffStart(&quot;unknown&quot;);</span><br><span class="line"> final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);</span><br><span class="line"> final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);</span><br><span class="line"> try &#123;</span><br><span class="line"> mNetworkPolicyManager.setDeviceIdleMode(false);</span><br><span class="line"> mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,</span><br><span class="line"> null, Process.myUid());</span><br><span class="line"> &#125; catch (RemoteException e) &#123;</span><br><span class="line"> &#125;</span><br><span class="line"> if (deepChanged) &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125;</span><br><span class="line"> if (lightChanged) &#123;</span><br><span class="line"> // 曾加mActiveIdleOpCount计数</span><br><span class="line"> incActiveIdleOps();</span><br><span class="line"> // 发送广播,最后执行mIdleStartedDoneReceiver</span><br><span class="line"> getContext().sendOrderedBroadcastAsUser(mLightIdleIntent, UserHandle.ALL,</span><br><span class="line"> null, mIdleStartedDoneReceiver, null, 0, null, null);</span><br><span class="line"> &#125;</span><br><span class="line"> // 减少mActiveIdleOpCount计数</span><br><span class="line"> decActiveIdleOps();</span><br><span class="line"> EventLogTags.writeDeviceIdleOffComplete();</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_REPORT_ACTIVE: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_TEMP_APP_WHITELIST_TIMEOUT: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_REPORT_MAINTENANCE_ACTIVITY: &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; break;</span><br><span class="line"> case MSG_FINISH_IDLE_OP: &#123;</span><br><span class="line"> decActiveIdleOps();</span><br><span class="line"> &#125; break;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>MyHandler中处理MSG_REPORT_IDLE_OFF消息主要是恢复MSG_REPORT_IDLE_ON时所做的限制操作,恢复网络,SyncManager,jobsheduler的执行。</p>
<h2 id="LIGHT-STATE-IDLE-MAINTENANCE-gt-LIGHT-STATE-IDLE"><a href="#LIGHT-STATE-IDLE-MAINTENANCE-gt-LIGHT-STATE-IDLE" class="headerlink" title="LIGHT_STATE_IDLE_MAINTENANCE -&gt; LIGHT_STATE_IDLE"></a>LIGHT_STATE_IDLE_MAINTENANCE -&gt; LIGHT_STATE_IDLE</h2><p>LIGHT_STATE_IDLE_MAINTENANCE状态恢复操作处理时,最后执行最后decActiveIdleOps(),同时发送的OrderedBroadcast也会执行mIdleStartedDoneReceiver最后也是调用decActiveIdleOps()处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">private final BroadcastReceiver mIdleStartedDoneReceiver = new BroadcastReceiver() &#123;</span><br><span class="line"> @Override public void onReceive(Context context, Intent intent) &#123;</span><br><span class="line"> if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,</span><br><span class="line"> mConstants.MIN_LIGHT_MAINTENANCE_TIME);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>mIdleStartedDoneReceiver中发送MSG_FINISH_IDLE_OP消息,进入decActiveIdleOps()中处理,检查当前是否有active的操作(Alarm,Job),如果没有则无需等定时器到期提前退出Maintenance windows。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">void decActiveIdleOps() &#123;</span><br><span class="line"> synchronized (this) &#123;</span><br><span class="line"> mActiveIdleOpCount--;</span><br><span class="line"> // 当前activie操作小于等于0,说明当前没有执行的操作,可以以前退出Maintenance windows </span><br><span class="line"> if (mActiveIdleOpCount &lt;= 0) &#123;</span><br><span class="line"> exitMaintenanceEarlyIfNeededLocked();</span><br><span class="line"> mActiveIdleWakeLock.release();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void exitMaintenanceEarlyIfNeededLocked() &#123;</span><br><span class="line"> if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE</span><br><span class="line"> || mLightState == LIGHT_STATE_PRE_IDLE) &#123;</span><br><span class="line"> // 当前是否有activie ops操作</span><br><span class="line"> if (isOpsInactiveLocked()) &#123;</span><br><span class="line"> final long now = SystemClock.elapsedRealtime();</span><br><span class="line"> if (mState == STATE_IDLE_MAINTENANCE) &#123;</span><br><span class="line"> stepIdleStateLocked(&quot;s:early&quot;);</span><br><span class="line"> &#125; else if (mLightState == LIGHT_STATE_PRE_IDLE) &#123;</span><br><span class="line"> stepLightIdleStateLocked(&quot;s:predone&quot;);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> stepLightIdleStateLocked(&quot;s:early&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>后续stepLightIdleStateLocked中的处理跟LIGHT_STATE_PRE_IDLE到LIGHT_STATE_IDLE状态切换一致。</p>
</content>
<summary type="html">
<p>Light Doze的状态切换如下图示:</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/powe
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power Management" scheme="http://robinheztto.com/tags/Power-Management/"/>
<category term="Doze" scheme="http://robinheztto.com/tags/Doze/"/>
</entry>
<entry>
<title>Android电源管理系列之Doze</title>
<link href="http://robinheztto.com/2017/09/11/android-power-doze-overview/"/>
<id>http://robinheztto.com/2017/09/11/android-power-doze-overview/</id>
<published>2017-09-11T03:36:35.000Z</published>
<updated>2018-06-24T16:24:25.000Z</updated>
<content type="html"><blockquote>
<p>从Android M开始,开始引入Doze和App standby两种省电技术以延长电池的使用寿命,其中Doze模式主要针对设备空闲的情况,而App standby针对于未使用的应用。<br>当设备处于灭屏且未充电状态,静止一段时间后就会进入Doze的空闲状态(前提是编译前已通过配置xml文件开启Doze功能),然后通过限制App访问网络,并推迟Syncs,Jobs,Alarm等工作来减少电池电量的消耗。而Appstandby,主要针对于不是经常使用的App,禁止其后台的网络活动,作业等行为。只要App在android M或更高版本的系统上运行,都会受到Doze和App Standby模式的约束。</p>
</blockquote>
<h1 id="Doze模式"><a href="#Doze模式" class="headerlink" title="Doze模式"></a>Doze模式</h1><p>下面是Doze模式的时序示意图,设备进入Doze模式必须满足三个前提条件,屏幕熄灭,未充电,静止一段时间。在进入Doze模式后,系统会周期性退出Doze空闲状态(下图的maintenance window),让App有机会完成被限制的活动,以获取更好的用户体验,随着时间的推移,系统调度maintenance窗口的频率会越来越低。</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/doze.png?raw=true" alt="doze"><br></div><br>Doze模式通过对应用活动的限制,来使系统在空闲状态下尽可能的休眠。</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/doze-limit.png?raw=true" alt="doze"><br></div><br>如上图示,当处于Doze Idle状态时,wakelock被disable,网络访问被禁止,Jobs与Syncs,Alarm都被推迟到maintenance window执行,GPS/WiFi扫描也被禁止。</p>
<h1 id="增强Doze模式"><a href="#增强Doze模式" class="headerlink" title="增强Doze模式"></a>增强Doze模式</h1><p>在Android N版本上,Doze模式有了进一步增强,加入了Light idle和Deep idle。相比于M版本,Android N进入Doze模式条件更加宽松,当手机处于未充电状态且灭屏一段时间(不一定是静止状态),就可以进入Light idle浅度休眠模式。</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/doze-diagram-1.png?raw=true" alt="doze"><br></div><br>Light idle与Deep idle独立运行的,系统会首先进入Light idle然后进入Deep idle,当进入Deep idle后,Light idle状态被忽略。下面是二种模式的比较:</p>
<table>
<thead>
<tr>
<th>IDLE程度</th>
<th>进入条件</th>
<th>对App的行为限制</th>
<th>退出条件</th>
<th>设备硬件要求</th>
</tr>
</thead>
<tbody>
<tr>
<td>Light IDLE</td>
<td>设备不充电,屏幕关闭</td>
<td>1.不能访问网络;<br>2.推迟作业和同步</td>
<td>激活屏幕,设备充电,Alarms定时时间到</td>
<td>无</td>
</tr>
<tr>
<td>Deep IDLE</td>
<td>设备不充电,屏幕关闭,设备保持静止一段时间</td>
<td>1.不能访问网络;<br>2.wake lock失效;<br>3.禁止GPS/WIFI 扫描;<br>4.Alarms推迟;<br>5.作业,同步推迟;</td>
<td>激活屏幕,设备充电,移动设备,Alarms定时时间到</td>
<td>具有SMD(Significant motion Dector),用于检测设备是否处于静止状态传感器</td>
</tr>
</tbody>
</table>
<h1 id="开启Doze功能"><a href="#开启Doze功能" class="headerlink" title="开启Doze功能"></a>开启Doze功能</h1><ol>
<li>安装GCM服务(可选)</li>
<li><p>打开Doze模式的配置开关(AOSP中默认关闭),修改如下配置</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/core/res/res/values/config.xml</span><br><span class="line"></span><br><span class="line">&lt;!-- Set this to true to enable the platform&apos;s auto-power-save modes like doze and</span><br><span class="line"> app standby. These are not enabled by default because they require a standard</span><br><span class="line"> cloud-to-device messaging service for apps to interact correctly with the modes</span><br><span class="line"> (such as to be able to deliver an instant message to the device even when it is</span><br><span class="line"> dozing). This should be enabled if you have such services and expect apps to</span><br><span class="line"> correctly use them when installed on your device. Otherwise, keep this disabled</span><br><span class="line"> so that applications can still use their own mechanisms. --&gt;</span><br><span class="line">&lt;bool name=&quot;config_enableAutoPowerModes&quot;&gt;true&lt;/bool&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>预装App/服务适配,重要的App/服务加入白名单(如果不能使用GCM服务,App又要求具有即使推送消息功能,那么最好加入到白名单中)</p>
</li>
</ol>
<h1 id="白名单"><a href="#白名单" class="headerlink" title="白名单"></a>白名单</h1><p>由于国内网络环境,Android设备基本上不能正常使用Google服务,但App又需要接收实时消息推送,所以系统提供了可以配置的白名单让App免于被Doze模式和App standby模式限制。</p>
<ol>
<li><p>预置应用,对于系统应用,需要默认加入到白名单中,修改<code>frameworks/base/data/etc/platform.xml</code>配置文件,如下所示:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- These are the standard packages that are white-listed to always have internet</span><br><span class="line"> access while in power save mode, even if they aren&apos;t in the foreground. --&gt;</span><br><span class="line">&lt;allow-in-power-save package=&quot;com.android.providers.downloads&quot; /&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>主动配置,配置的白名单的app数据保存在<code>/data/system/deviceidle.xml</code>。</p>
</li>
</ol>
<ul>
<li>用户可以通过设置&gt;电池&gt;电池优化来手动配置白名单。</li>
<li>App发送Intent,ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS直接导航用户到电池优化界面。</li>
<li>App申请REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,通过发送Intent(ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)触发请求加入白名单的对话框,用户在对话框中选择是或否在决定是否加入白名单(推荐这种方式)</li>
</ul>
<h1 id="调试"><a href="#调试" class="headerlink" title="调试"></a>调试</h1><p><strong>在调试中所有状态都可通过命令<code>adb shell dumpsys deviceidle</code>来查看</strong></p>
<ol>
<li>设置手机未充电状态<br><code>$ adb shell dumpsys battery unplug</code></li>
<li>查看手机充电状态,<code>AC powered:</code>与<code>USB powered:</code>为false说明设置成功<br><code>$ adb shell dumpsys battery</code></li>
<li>enable Doze<br><code>$ adb shell dumpsys deviceidle enable light/deep/all</code></li>
<li>设置Doze模式<br><code>$ adb shell dumpsys deviceidle step light/deep</code></li>
<li>强制直接进入Deep IDLE状态<br><code>$ adb shell dumpsys deviceidle force-idle</code></li>
<li>disable Doze<br><code>$ adb shell dumpsys deviceidle disable</code></li>
<li>reset battery状态<br><code>$ adb shell dumpsys battery reset</code></li>
</ol>
<h1 id="DeviceIdleController"><a href="#DeviceIdleController" class="headerlink" title="DeviceIdleController"></a>DeviceIdleController</h1><p>DeviceIdleController是在system_server中启动的负责管理Doze模式的系统服务。如下图示,DeviceIdleController服务驱动Doze状态机,通过状态的轮转,以发送广播与调用setidle方法的方式通知关联模块对不同状态做出不同的策略。</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/DeviceIdleController.png?raw=true" alt="DeviceIdleController"><br></div><br>在system_server启动过程,执行startOtherServices时,创建并启动了DeviceIdleController服务。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/java/com/android/server/SystemServer.java</span><br><span class="line"></span><br><span class="line">private void startOtherServices() &#123;</span><br><span class="line"> ......</span><br><span class="line"> mSystemServiceManager.startService(DeviceIdleController.class);</span><br><span class="line"> ......</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>DeviceIdleController继承于SystemService,并且实现AnyMotionDetector.DeviceIdleCallback接口,该接口主要用来监测设备的运动状态。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/DeviceIdleController.java</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Keeps track of device idleness and drives low power mode based on that.</span><br><span class="line"> */</span><br><span class="line">public class DeviceIdleController extends SystemService</span><br><span class="line"> implements AnyMotionDetector.DeviceIdleCallback &#123;</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>mSystemServiceManager.startService(DeviceIdleController.class)利用反射的方式构造DeviceIdleController服务,然后调用其onStart()方法,首先看构造方法的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/DeviceIdleController.java</span><br><span class="line"></span><br><span class="line">public DeviceIdleController(Context context) &#123;</span><br><span class="line"> super(context);</span><br><span class="line"> mConfigFile = new AtomicFile(new File(getSystemDir(), &quot;deviceidle.xml&quot;));</span><br><span class="line"> mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>DeviceIdleController构造方法中,新建对应/data/system/deviceidle.xml文件的原子操作文件对象,并且创建关联后台线程的mHandler处理消息。接下来看onStart()方法的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/DeviceIdleController.java</span><br><span class="line"></span><br><span class="line">public void onStart() &#123;</span><br><span class="line"> final PackageManager pm = getContext().getPackageManager();</span><br><span class="line"></span><br><span class="line"> synchronized (this) &#123;</span><br><span class="line"> // 读取定义在frameworks/base/core/res/res/values/config.xml文件中的config_enableAutoPowerModes</span><br><span class="line"> // 标志是否打开Doze模式 </span><br><span class="line"> mLightEnabled = mDeepEnabled = getContext().getResources().getBoolean(</span><br><span class="line"> com.android.internal.R.bool.config_enableAutoPowerModes);</span><br><span class="line"> SystemConfig sysConfig = SystemConfig.getInstance();</span><br><span class="line"> // 读取Doze模式下的系统应用白名单配置</span><br><span class="line"> // 该配置在etc/permissions/platform.xml文件中以tag:allow-in-power-save-except-idle的形式定义</span><br><span class="line"> ArraySet&lt;String&gt; allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle();</span><br><span class="line"> for (int i=0; i&lt;allowPowerExceptIdle.size(); i++) &#123;</span><br><span class="line"> String pkg = allowPowerExceptIdle.valueAt(i);</span><br><span class="line"> try &#123;</span><br><span class="line"> ApplicationInfo ai = pm.getApplicationInfo(pkg,</span><br><span class="line"> PackageManager.MATCH_SYSTEM_ONLY);</span><br><span class="line"> int appid = UserHandle.getAppId(ai.uid);</span><br><span class="line"> mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);</span><br><span class="line"> mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);</span><br><span class="line"> &#125; catch (PackageManager.NameNotFoundException e) &#123;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> // 读取Doze模式及Appstandby模式下的系统应用白名单配置</span><br><span class="line"> // 该配置在etc/permissions/platform.xml文件中以tag:allow-in-power-save的形式定义</span><br><span class="line"> ArraySet&lt;String&gt; allowPower = sysConfig.getAllowInPowerSave();</span><br><span class="line"> for (int i=0; i&lt;allowPower.size(); i++) &#123;</span><br><span class="line"> String pkg = allowPower.valueAt(i);</span><br><span class="line"> try &#123;</span><br><span class="line"> ApplicationInfo ai = pm.getApplicationInfo(pkg,</span><br><span class="line"> PackageManager.MATCH_SYSTEM_ONLY);</span><br><span class="line"> int appid = UserHandle.getAppId(ai.uid);</span><br><span class="line"> // These apps are on both the whitelist-except-idle as well</span><br><span class="line"> // as the full whitelist, so they apply in all cases.</span><br><span class="line"> mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);</span><br><span class="line"> mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);</span><br><span class="line"> mPowerSaveWhitelistApps.put(ai.packageName, appid);</span><br><span class="line"> mPowerSaveWhitelistSystemAppIds.put(appid, true);</span><br><span class="line"> &#125; catch (PackageManager.NameNotFoundException e) &#123;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 更新常量设置</span><br><span class="line"> mConstants = new Constants(mHandler, getContext().getContentResolver());</span><br><span class="line"> // 读取Doze模式及Appstandby模式下的用户应用白名单配置</span><br><span class="line"> // 该配置在data/system/deviceidle.xml文件中以tag:wl的形式定义</span><br><span class="line"> readConfigFileLocked();</span><br><span class="line"> // 合并系统应用及用户应用白名单,并设置到PowerManager及AlarmManager中</span><br><span class="line"> updateWhitelistAppIdsLocked();</span><br><span class="line"></span><br><span class="line"> // 初始化相关成员的状态</span><br><span class="line"> mNetworkConnected = true;</span><br><span class="line"> mScreenOn = true;</span><br><span class="line"> // Start out assuming we are charging. If we aren&apos;t, we will at least get</span><br><span class="line"> // a battery update the next time the level drops.</span><br><span class="line"> mCharging = true;</span><br><span class="line"> mState = STATE_ACTIVE;</span><br><span class="line"> mLightState = LIGHT_STATE_ACTIVE;</span><br><span class="line"> mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 发布BinderService与LocalService对象,提供接口给其他进程或本进程内其他服务</span><br><span class="line"> mBinderService = new BinderService();</span><br><span class="line"> publishBinderService(Context.DEVICE_IDLE_CONTROLLER, mBinderService);</span><br><span class="line"> publishLocalService(LocalService.class, new LocalService());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>onStart()中初始化了白名单设置,如下所示分成三类:</p>
<ol>
<li>System-excidle (system app) : used for doze<br>ArrayMap<string, interger=""> mPowerSaveWhitelistAppsExceptIdle<br>String: packageName<br>Interger: app Uid<br>From etc/permissions/platform.xml tag: allow-in-power-save-except-idle (SystemConfig.mAllowInPowerSaveExceptIdle)</string,></li>
<li>System (system app) : used for doze &amp; app standby<br>ArrayMap<string, interger=""> mPowerSaveWhitelistApps<br>From etc/permissions/platform.xml tag : allow-in-power-save (SystemConfig.mAllowInPowerSave)</string,></li>
<li>User : used for doze &amp; app standby<br>ArrayMap<string,interger> mPowerSaveWhitelistUserApps<br>From data/system/deviceidle.xml tag: wl</string,interger></li>
</ol>
<p>当所有系统服务就绪后,会执行<code>mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);</code>回调到DeviceIdleController的onBootPhase()方法中,下面继续看onBootPhase()。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">public void onBootPhase(int phase) &#123;</span><br><span class="line"> if (phase == PHASE_SYSTEM_SERVICES_READY) &#123;</span><br><span class="line"> synchronized (this) &#123;</span><br><span class="line"> // 获取相关的系统服务 </span><br><span class="line"> mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);</span><br><span class="line"> mBatteryStats = BatteryStatsService.getService();</span><br><span class="line"> mLocalPowerManager = getLocalService(PowerManagerInternal.class);</span><br><span class="line"> mPowerManager = getContext().getSystemService(PowerManager.class);</span><br><span class="line"> // 创建WakeLock,用于maintenance windows时期防止系统休眠</span><br><span class="line"> mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,</span><br><span class="line"> &quot;deviceidle_maint&quot;);</span><br><span class="line"> // 设置WakeLock引用计数为false</span><br><span class="line"> mActiveIdleWakeLock.setReferenceCounted(false);</span><br><span class="line"> mConnectivityService = (ConnectivityService)ServiceManager.getService(</span><br><span class="line"> Context.CONNECTIVITY_SERVICE);</span><br><span class="line"> mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);</span><br><span class="line"> mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(</span><br><span class="line"> ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));</span><br><span class="line"> mDisplayManager = (DisplayManager) getContext().getSystemService(</span><br><span class="line"> Context.DISPLAY_SERVICE);</span><br><span class="line"> mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);</span><br><span class="line"> // 读取定义在frameworks/base/core/res/res/values/config.xml文件中的config_autoPowerModeAnyMotionSensor</span><br><span class="line"> // 获取传感器ID,没有则继续获取</span><br><span class="line"> int sigMotionSensorId = getContext().getResources().getInteger(</span><br><span class="line"> com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);</span><br><span class="line"> if (sigMotionSensorId &gt; 0) &#123;</span><br><span class="line"> mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);</span><br><span class="line"> &#125;</span><br><span class="line"> // 读取定义在frameworks/base/core/res/res/values/config.xml文件中的config_autoPowerModePreferWristTilt</span><br><span class="line"> // 有设置,则获取传感器ID,根据ID获取传感器实例,没有则继续获取</span><br><span class="line"> if (mMotionSensor == null &amp;&amp; getContext().getResources().getBoolean(</span><br><span class="line"> com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) &#123;</span><br><span class="line"> mMotionSensor = mSensorManager.getDefaultSensor(</span><br><span class="line"> Sensor.TYPE_WRIST_TILT_GESTURE, true);</span><br><span class="line"> &#125;</span><br><span class="line"> // 最后,获取TYPE_SIGNIFICANT_MOTION传感器,获取成功则可以进入Deep Doze模式,没有则只能进入Light Doze模式</span><br><span class="line"> if (mMotionSensor == null) &#123;</span><br><span class="line"> // As a last ditch, fall back to SMD.</span><br><span class="line"> mMotionSensor = mSensorManager.getDefaultSensor(</span><br><span class="line"> Sensor.TYPE_SIGNIFICANT_MOTION, true);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> if (getContext().getResources().getBoolean(</span><br><span class="line"> com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) &#123;</span><br><span class="line"> mLocationManager = (LocationManager) getContext().getSystemService(</span><br><span class="line"> Context.LOCATION_SERVICE);</span><br><span class="line"> mLocationRequest = new LocationRequest()</span><br><span class="line"> .setQuality(LocationRequest.ACCURACY_FINE)</span><br><span class="line"> .setInterval(0)</span><br><span class="line"> .setFastestInterval(0)</span><br><span class="line"> .setNumUpdates(1);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 获取运动传感器检测角度的阀值,并创建AnyMotionDetector</span><br><span class="line"> float angleThreshold = getContext().getResources().getInteger(</span><br><span class="line"> com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;</span><br><span class="line"> mAnyMotionDetector = new AnyMotionDetector(</span><br><span class="line"> (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),</span><br><span class="line"> mHandler, mSensorManager, this, angleThreshold);</span><br><span class="line"></span><br><span class="line"> // light mode与deep mode的Intent,用于通知其他模块进入light/deep模式 </span><br><span class="line"> mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);</span><br><span class="line"> mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY</span><br><span class="line"> | Intent.FLAG_RECEIVER_FOREGROUND);</span><br><span class="line"> mLightIdleIntent = new Intent(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);</span><br><span class="line"> mLightIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY</span><br><span class="line"> | Intent.FLAG_RECEIVER_FOREGROUND);</span><br><span class="line"></span><br><span class="line"> // 注册BATTERY_CHANGED广播 </span><br><span class="line"> IntentFilter filter = new IntentFilter();</span><br><span class="line"> filter.addAction(Intent.ACTION_BATTERY_CHANGED);</span><br><span class="line"> getContext().registerReceiver(mReceiver, filter);</span><br><span class="line"></span><br><span class="line"> // 注册PACKAGE_REMOVED广播 </span><br><span class="line"> filter = new IntentFilter();</span><br><span class="line"> filter.addAction(Intent.ACTION_PACKAGE_REMOVED);</span><br><span class="line"> filter.addDataScheme(&quot;package&quot;);</span><br><span class="line"> getContext().registerReceiver(mReceiver, filter);</span><br><span class="line"></span><br><span class="line"> // 注册网络变化广播</span><br><span class="line"> filter = new IntentFilter();</span><br><span class="line"> filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);</span><br><span class="line"> getContext().registerReceiver(mReceiver, filter);</span><br><span class="line"></span><br><span class="line"> // 设置PowerManager,AlarmManager中Doze模式白名单应用</span><br><span class="line"> mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);</span><br><span class="line"> mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);</span><br><span class="line"> // 注册屏幕亮灭监听</span><br><span class="line"> mDisplayManager.registerDisplayListener(mDisplayListener, null);</span><br><span class="line"> // 更新当前屏幕亮灭状态</span><br><span class="line"> updateDisplayLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> // 更新当前网络连接状态</span><br><span class="line"> updateConnectivityState(null);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>传感器选用规则:<br>Doze 模式启动之前会对当前设备传感器进行检查,以决定doze模式的深度:<br>步骤1:检查com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor,如果有设置,则获取传感器ID,根据ID获取传感器实例,没有的话跳到步骤2。<br>步骤2:检查com.android.internal.R.bool.config_autoPowerModePreferWristTilt,如果有设置,则获取传感器ID,根据ID获取传感器实例,没有的话跳到步骤3。<br>步骤3:获取TYPE_SIGNIFICANT_MOTION传感器,获取成功则有条件可以进入Deep Doze模式,没有则只能进入Light Doze模式。</p>
</content>
<summary type="html">
<blockquote>
<p>从Android M开始,开始引入Doze和App standby两种省电技术以延长电池的使用寿命,其中Doze模式主要针对设备空闲的情况,而App standby针对于未使用的应用。<br>当设备处于灭屏且未充电状态,静止一段时间后就会进入Doz
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power Management" scheme="http://robinheztto.com/tags/Power-Management/"/>
<category term="Doze" scheme="http://robinheztto.com/tags/Doze/"/>
</entry>
<entry>
<title>Android电源管理系列之PowerManagerService(二)</title>
<link href="http://robinheztto.com/2017/06/16/android-power-pms-2/"/>
<id>http://robinheztto.com/2017/06/16/android-power-pms-2/</id>
<published>2017-06-16T03:23:25.000Z</published>
<updated>2018-01-07T04:07:05.000Z</updated>
<content type="html"><h1 id="WakeLock机制"><a href="#WakeLock机制" class="headerlink" title="WakeLock机制"></a>WakeLock机制</h1><h2 id="PowerManager-WakeLock"><a href="#PowerManager-WakeLock" class="headerlink" title="PowerManager.WakeLock"></a>PowerManager.WakeLock</h2><p>为了延长电池的使用寿命,Android设备会在一段时间后使屏幕变暗,然后关闭屏幕显示,直至停止CPU进入休眠。WakeLock是Android提供的唤醒锁机制,用来保持CPU运行或避免屏幕变暗/关闭以及避免键盘背光灯熄灭。</p>
<p>唤醒锁的类型:</p>
<table>
<thead>
<tr>
<th>Flag</th>
<th>CPU</th>
<th>Screen</th>
<th>Keyboard</th>
</tr>
</thead>
<tbody>
<tr>
<td>PARTIAL_WAKE_LOCK</td>
<td>on</td>
<td>off</td>
<td>off</td>
</tr>
<tr>
<td>SCREEN_DIM_WAKE_LOCK</td>
<td>on</td>
<td>Dim</td>
<td>off</td>
</tr>
<tr>
<td>SCREEN_BRIGHT_WAKE_LOCK</td>
<td>on</td>
<td>Bright</td>
<td>off</td>
</tr>
<tr>
<td>FULL_WAKE_LOCK</td>
<td>on</td>
<td>Bright</td>
<td>on</td>
</tr>
</tbody>
</table>
<p>如果是PARTIAL_WAKE_LOCK,无论屏幕的状态或是按下电源键, CPU都将正常工作。如果是其它的唤醒锁,设备会在用户按下电源钮后停止工作进入休眠状态。以上四种锁,除了PARTIAL_WAKE_LOCK,其余的锁在API level 17已经被deprecated了。</p>
<p>唤醒锁的使用:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">权限申明:</span><br><span class="line">&lt;uses-permission android:name=&quot;android.permission.WAKE_LOCK&quot; /&gt;</span><br><span class="line">&lt;uses-permission android:name=&quot;android.permission.DEVICE_POWER&quot;/&gt;</span><br><span class="line"></span><br><span class="line">代码使用:</span><br><span class="line">PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);</span><br><span class="line">PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, &quot;My Tag&quot;);</span><br><span class="line">wl.acquire(); //acquire时尽量申明timeout时间</span><br><span class="line">//......</span><br><span class="line">wl.release();</span><br></pre></td></tr></table></figure></p>
<p>在应用程序中使用WakeLock时必须申明权限,acquire请求唤醒锁时尽量设置timeout时间释放WakeLock,以避免长时间持有WakeLock导致系统无法休眠。</p>
<p>唤醒锁的实现:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/core/java/android/os/PowerManager.java</span><br><span class="line"></span><br><span class="line">public final class WakeLock &#123;</span><br><span class="line"> private int mFlags;</span><br><span class="line"> private String mTag;</span><br><span class="line"> private final String mPackageName;</span><br><span class="line"> private final IBinder mToken;</span><br><span class="line"> private int mCount;</span><br><span class="line"> private boolean mRefCounted = true;</span><br><span class="line"> private boolean mHeld;</span><br><span class="line"> private WorkSource mWorkSource;</span><br><span class="line"> private String mHistoryTag;</span><br><span class="line"> private final String mTraceName;</span><br><span class="line"> ......</span><br><span class="line"> WakeLock(int flags, String tag, String packageName) &#123;</span><br><span class="line"> mFlags = flags;</span><br><span class="line"> mTag = tag;</span><br><span class="line"> mPackageName = packageName;</span><br><span class="line"> mToken = new Binder();</span><br><span class="line"> mTraceName = &quot;WakeLock (&quot; + mTag + &quot;)&quot;;</span><br><span class="line"> &#125;</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="updatePowerStateLocked"><a href="#updatePowerStateLocked" class="headerlink" title="updatePowerStateLocked"></a>updatePowerStateLocked</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">protected void updatePowerStateLocked() &#123;</span><br><span class="line"> // 服务没有ready,mDirty值没有设置情况下不做更新操作</span><br><span class="line"> if (!mSystemReady || mDirty == 0) &#123;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"> if (!Thread.holdsLock(mLock)) &#123;</span><br><span class="line"> Slog.wtf(TAG, &quot;Power manager lock was not held when calling updatePowerStateLocked&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> try &#123;</span><br><span class="line"> // Phase 0: 更新基本状态</span><br><span class="line"> updateIsPoweredLocked(mDirty);</span><br><span class="line"> updateStayOnLocked(mDirty);</span><br><span class="line"> updateScreenBrightnessBoostLocked(mDirty);</span><br><span class="line"></span><br><span class="line"> // Phase 1: Update wakefulness.</span><br><span class="line"> // Loop because the wake lock and user activity computations are influenced</span><br><span class="line"> // by changes in wakefulness.</span><br><span class="line"> final long now = SystemClock.uptimeMillis();</span><br><span class="line"> int dirtyPhase2 = 0;</span><br><span class="line"> for (;;) &#123;</span><br><span class="line"> int dirtyPhase1 = mDirty;</span><br><span class="line"> dirtyPhase2 |= dirtyPhase1;</span><br><span class="line"> mDirty = 0;</span><br><span class="line"></span><br><span class="line"> updateWakeLockSummaryLocked(dirtyPhase1);</span><br><span class="line"> updateUserActivitySummaryLocked(now, dirtyPhase1);</span><br><span class="line"> if (!updateWakefulnessLocked(dirtyPhase1)) &#123;</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // Phase 2: Update display power state.</span><br><span class="line"> boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);</span><br><span class="line"></span><br><span class="line"> // Phase 3: Update dream state (depends on display ready signal).</span><br><span class="line"> updateDreamLocked(dirtyPhase2, displayBecameReady);</span><br><span class="line"></span><br><span class="line"> // Phase 4: Send notifications, if needed.</span><br><span class="line"> finishWakefulnessChangeIfNeededLocked();</span><br><span class="line"></span><br><span class="line"> // Phase 5: Update suspend blocker.</span><br><span class="line"> // Because we might release the last suspend blocker here, we need to make sure</span><br><span class="line"> // we finished everything else first!</span><br><span class="line"> updateSuspendBlockerLocked();</span><br><span class="line"> &#125; finally &#123;</span><br><span class="line"> Trace.traceEnd(Trace.TRACE_TAG_POWER);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>首先来看updateIsPoweredLocked(mDirty);<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">private void updateIsPoweredLocked(int dirty) &#123;</span><br><span class="line"> if ((dirty &amp; DIRTY_BATTERY_STATE) != 0) &#123;</span><br><span class="line"> final boolean wasPowered = mIsPowered;</span><br><span class="line"> final int oldPlugType = mPlugType;</span><br><span class="line"> final boolean oldLevelLow = mBatteryLevelLow;</span><br><span class="line"> mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);</span><br><span class="line"> mPlugType = mBatteryManagerInternal.getPlugType();</span><br><span class="line"> mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();</span><br><span class="line"> mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();</span><br><span class="line"></span><br><span class="line"> if (wasPowered != mIsPowered || oldPlugType != mPlugType) &#123;</span><br><span class="line"> mDirty |= DIRTY_IS_POWERED;</span><br><span class="line"></span><br><span class="line"> // Update wireless dock detection state.</span><br><span class="line"> final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(</span><br><span class="line"> mIsPowered, mPlugType, mBatteryLevel);</span><br><span class="line"></span><br><span class="line"> // Treat plugging and unplugging the devices as a user activity.</span><br><span class="line"> // Users find it disconcerting when they plug or unplug the device</span><br><span class="line"> // and it shuts off right away.</span><br><span class="line"> // Some devices also wake the device when plugged or unplugged because</span><br><span class="line"> // they don&apos;t have a charging LED.</span><br><span class="line"> final long now = SystemClock.uptimeMillis();</span><br><span class="line"> if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,</span><br><span class="line"> dockedOnWirelessCharger)) &#123;</span><br><span class="line"> wakeUpNoUpdateLocked(now, &quot;android.server.power:POWER&quot;, Process.SYSTEM_UID,</span><br><span class="line"> mContext.getOpPackageName(), Process.SYSTEM_UID);</span><br><span class="line"> &#125;</span><br><span class="line"> userActivityNoUpdateLocked(</span><br><span class="line"> now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);</span><br><span class="line"></span><br><span class="line"> // Tell the notifier whether wireless charging has started so that</span><br><span class="line"> // it can provide feedback to the user.</span><br><span class="line"> //Bug293654, zhanghong.wt, modify, 20170914, modify no notificatin ring while plugging USB</span><br><span class="line"> if (dockedOnWirelessCharger || (mIsPowered &amp;&amp; oldPlugType != mPlugType&amp;&amp;(&quot;1&quot;.equals(SystemProperties.get(&quot;sys.boot_completed&quot;))))) &#123;</span><br><span class="line"> mNotifier.onWirelessChargingStarted();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) &#123;</span><br><span class="line"> if (oldLevelLow != mBatteryLevelLow &amp;&amp; !mBatteryLevelLow) &#123;</span><br><span class="line"> if (DEBUG_SPEW) &#123;</span><br><span class="line"> Slog.d(TAG, &quot;updateIsPoweredLocked: resetting low power snooze&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"> mAutoLowPowerModeSnoozing = false;</span><br><span class="line"> &#125;</span><br><span class="line"> updateLowPowerModeLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</content>
<summary type="html">
<h1 id="WakeLock机制"><a href="#WakeLock机制" class="headerlink" title="WakeLock机制"></a>WakeLock机制</h1><h2 id="PowerManager-WakeLock"><a href="#
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power Management" scheme="http://robinheztto.com/tags/Power-Management/"/>
<category term="PowerManagerService" scheme="http://robinheztto.com/tags/PowerManagerService/"/>
</entry>
<entry>
<title>Android电源管理系列之PowerManagerService(一)</title>
<link href="http://robinheztto.com/2017/06/14/android-power-pms-1/"/>
<id>http://robinheztto.com/2017/06/14/android-power-pms-1/</id>
<published>2017-06-14T07:19:20.000Z</published>
<updated>2018-01-07T04:07:05.000Z</updated>
<content type="html"><blockquote>
<p>PowerManagerService提供Android系统的电源管理服务,主要功能是控制系统待机状态,屏幕显示,亮度调节,光线/距离传感器的控制等。</p>
<p>相关代码在以下文件中:<br>frameworks/base/services/java/com/android/server/SystemServer.java<br>frameworks/base/core/java/android/os/PowerManager.java<br>frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java<br>frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp<br>frameworks/base/core/java/android/os/PowerManagerInternal.java<br>frameworks/base/services/core/java/com/android/server/power/Notifier.java<br>device/qcom/common/power/power.c<br>system/core/libsuspend/autosuspend.c<br>hardware/libhardware_legacy/power/power.c</p>
</blockquote>
<h1 id="初始化流程"><a href="#初始化流程" class="headerlink" title="初始化流程"></a>初始化流程</h1><p>跟其他系统服务一样,PowerManagerService也是继承于SystemService并通过SystemServer启动。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">public final class PowerManagerService extends SystemService</span><br><span class="line"> implements Watchdog.Monitor &#123;</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt; frameworks/base/services/java/com/android/server/SystemServer.java</span><br><span class="line"></span><br><span class="line">private void startBootstrapServices() &#123;</span><br><span class="line"> ......</span><br><span class="line"> mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>在SystemServer的startBootstrapServices中,通过SystemServiceManager.startService启动了PowerManagerService,下面首先来看PowerManagerService构造方法。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">public PowerManagerService(Context context) &#123;</span><br><span class="line"> super(context);</span><br><span class="line"> // mContext赋值为SystemContext</span><br><span class="line"> mContext = context;</span><br><span class="line"> // 创建消息处理线程并启动,创建关联消息处理线程的handler对象</span><br><span class="line"> mHandlerThread = new ServiceThread(TAG,</span><br><span class="line"> Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);</span><br><span class="line"> mHandlerThread.start();</span><br><span class="line"> mHandler = new PowerManagerHandler(mHandlerThread.getLooper());</span><br><span class="line"> qcNsrmPowExt = new QCNsrmPowerExtension(this);</span><br><span class="line"> synchronized (mLock) &#123;</span><br><span class="line"> // 创建&quot;PowerManagerService.WakeLocks&quot;的SuspendBlocker</span><br><span class="line"> mWakeLockSuspendBlocker = createSuspendBlockerLocked(&quot;PowerManagerService.WakeLocks&quot;);</span><br><span class="line"> // 创建&quot;PowerManagerService.Display&quot;的SuspendBlocker</span><br><span class="line"> mDisplaySuspendBlocker = createSuspendBlockerLocked(&quot;PowerManagerService.Display&quot;);</span><br><span class="line"> // 请求DisplaySuspendBlocker,禁止系统进入休眠</span><br><span class="line"> mDisplaySuspendBlocker.acquire();</span><br><span class="line"> mHoldingDisplaySuspendBlocker = true;</span><br><span class="line"> mHalAutoSuspendModeEnabled = false;</span><br><span class="line"> mHalInteractiveModeEnabled = true;</span><br><span class="line"> // 设置mWakefulness为唤醒状态</span><br><span class="line"> mWakefulness = WAKEFULNESS_AWAKE;</span><br><span class="line"> // 进入到native层初始化</span><br><span class="line"> nativeInit();</span><br><span class="line"> nativeSetAutoSuspend(false);</span><br><span class="line"> nativeSetInteractive(true);</span><br><span class="line"> nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>PowerManagerService构造函数中首先创建了处理消息的进程及对应的handler对象以进行消息处理,然后创建SuspendBlocker对象,用于WakeLocks与Display,并设置mWakefulness的初始状态为WAKEFULNESS_AWAKE,最后进入到native层初始化。下面先看一下关于mWakefulness的定义。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/core/java/android/os/PowerManagerInternal.java</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 设备处于休眠状态,只能被wakeUp()唤醒.</span><br><span class="line"> */</span><br><span class="line">public static final int WAKEFULNESS_ASLEEP = 0;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 设备处于正常工作(fully awake)状态.</span><br><span class="line"> */</span><br><span class="line">public static final int WAKEFULNESS_AWAKE = 1;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 设备处于播放屏保状态.</span><br><span class="line"> */</span><br><span class="line">public static final int WAKEFULNESS_DREAMING = 2;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 设备处于doze状态,只有低耗电的屏保可以运行,其他应用被挂起.</span><br><span class="line"> */</span><br><span class="line">public static final int WAKEFULNESS_DOZING = 3;</span><br></pre></td></tr></table></figure></p>
<p>继续回到PowerManagerService构造函数的native初始化中,首先来看nativeInit的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp</span><br><span class="line"></span><br><span class="line">static const JNINativeMethod gPowerManagerServiceMethods[] = &#123;</span><br><span class="line"> /* name, signature, funcPtr */</span><br><span class="line"> &#123; &quot;nativeInit&quot;, &quot;()V&quot;,</span><br><span class="line"> (void*) nativeInit &#125;,</span><br><span class="line"> &#123; &quot;nativeAcquireSuspendBlocker&quot;, &quot;(Ljava/lang/String;)V&quot;,</span><br><span class="line"> (void*) nativeAcquireSuspendBlocker &#125;,</span><br><span class="line"> &#123; &quot;nativeReleaseSuspendBlocker&quot;, &quot;(Ljava/lang/String;)V&quot;,</span><br><span class="line"> (void*) nativeReleaseSuspendBlocker &#125;,</span><br><span class="line"> &#123; &quot;nativeSetInteractive&quot;, &quot;(Z)V&quot;,</span><br><span class="line"> (void*) nativeSetInteractive &#125;,</span><br><span class="line"> &#123; &quot;nativeSetAutoSuspend&quot;, &quot;(Z)V&quot;,</span><br><span class="line"> (void*) nativeSetAutoSuspend &#125;,</span><br><span class="line"> &#123; &quot;nativeSendPowerHint&quot;, &quot;(II)V&quot;,</span><br><span class="line"> (void*) nativeSendPowerHint &#125;,</span><br><span class="line"> &#123; &quot;nativeSetFeature&quot;, &quot;(II)V&quot;,</span><br><span class="line"> (void*) nativeSetFeature &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>PowerManagerService中的native方法定义如上,nativeInit即调用nativeInit()。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp</span><br><span class="line"></span><br><span class="line">static void nativeInit(JNIEnv* env, jobject obj) &#123;</span><br><span class="line"> // 创建一个全局对象,引用PMS</span><br><span class="line"> gPowerManagerServiceObj = env-&gt;NewGlobalRef(obj);</span><br><span class="line"> // 利用hw_get_module加载power模块</span><br><span class="line"> status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,</span><br><span class="line"> (hw_module_t const**)&amp;gPowerModule);</span><br><span class="line"> if (!err) &#123;</span><br><span class="line"> gPowerModule-&gt;init(gPowerModule);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> ALOGE(&quot;Couldn&apos;t load %s module (%s)&quot;, POWER_HARDWARE_MODULE_ID, strerror(-err));</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>nativeInit的主要任务时装载power模块,该模块由厂商实现,以高通为例,如下。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; device/qcom/common/power/power.c</span><br><span class="line"></span><br><span class="line">static struct hw_module_methods_t power_module_methods = &#123;</span><br><span class="line"> .open = NULL,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">struct power_module HAL_MODULE_INFO_SYM = &#123;</span><br><span class="line"> .common = &#123;</span><br><span class="line"> .tag = HARDWARE_MODULE_TAG,</span><br><span class="line"> .module_api_version = POWER_MODULE_API_VERSION_0_2,</span><br><span class="line"> .hal_api_version = HARDWARE_HAL_API_VERSION,</span><br><span class="line"> .id = POWER_HARDWARE_MODULE_ID,</span><br><span class="line"> .name = &quot;QCOM Power HAL&quot;,</span><br><span class="line"> .author = &quot;Qualcomm&quot;,</span><br><span class="line"> .methods = &amp;power_module_methods,</span><br><span class="line"> &#125;,</span><br><span class="line"></span><br><span class="line"> .init = power_init,</span><br><span class="line"> .powerHint = power_hint,</span><br><span class="line"> .setInteractive = set_interactive,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>power_module中实现了init,powerHint,setInteractive,nativeInit最终调用到HAL power模块的power_init具体实现中。接着看native初始化nativeSetAutoSuspend的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp</span><br><span class="line"></span><br><span class="line">static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) &#123;</span><br><span class="line"> if (enable) &#123;</span><br><span class="line"> ALOGD_IF_SLOW(100, &quot;Excessive delay in autosuspend_enable() while turning screen off&quot;);</span><br><span class="line"> autosuspend_enable();</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> ALOGD_IF_SLOW(100, &quot;Excessive delay in autosuspend_disable() while turning screen on&quot;);</span><br><span class="line"> autosuspend_disable();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt; system/core/libsuspend/autosuspend.c</span><br><span class="line"></span><br><span class="line">int autosuspend_disable(void)</span><br><span class="line">&#123;</span><br><span class="line"> int ret;</span><br><span class="line"></span><br><span class="line"> ret = autosuspend_init();</span><br><span class="line"> if (ret) &#123;</span><br><span class="line"> return ret;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> ALOGV(&quot;autosuspend_disable\n&quot;);</span><br><span class="line"></span><br><span class="line"> if (!autosuspend_enabled) &#123;</span><br><span class="line"> return 0;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> ret = autosuspend_ops-&gt;disable();</span><br><span class="line"> if (ret) &#123;</span><br><span class="line"> return ret;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> autosuspend_enabled = false;</span><br><span class="line"> return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>nativeSetAutoSuspend最终调用到libsuspend(参考Android电源管理系列之libsuspend)的autosuspend_disable禁止系统休眠。继续看native初始化nativeSetInteractive,nativeSetFeature的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp</span><br><span class="line"></span><br><span class="line">static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) &#123;</span><br><span class="line"> if (gPowerModule) &#123;</span><br><span class="line"> if (enable) &#123;</span><br><span class="line"> ALOGD_IF_SLOW(20, &quot;Excessive delay in setInteractive(true) while turning screen on&quot;);</span><br><span class="line"> gPowerModule-&gt;setInteractive(gPowerModule, true);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> ALOGD_IF_SLOW(20, &quot;Excessive delay in setInteractive(false) while turning screen off&quot;);</span><br><span class="line"> gPowerModule-&gt;setInteractive(gPowerModule, false);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) &#123;</span><br><span class="line"> int data_param = data;</span><br><span class="line"></span><br><span class="line"> if (gPowerModule &amp;&amp; gPowerModule-&gt;setFeature) &#123;</span><br><span class="line"> gPowerModule-&gt;setFeature(gPowerModule, (feature_t)featureId, data_param);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>同nativeInit一样,最终都是调用到HAL power模块的具体实现中。以上是构造函数的分析流程,下面继续看PowerManagerService在系统启动过程中回调onStart(),onBootPhase(),systemReady()的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">public void onStart() &#123;</span><br><span class="line"> publishBinderService(Context.POWER_SERVICE, new BinderService());</span><br><span class="line"> publishLocalService(PowerManagerInternal.class, new LocalService());</span><br><span class="line"></span><br><span class="line"> Watchdog.getInstance().addMonitor(this);</span><br><span class="line"> Watchdog.getInstance().addThread(mHandler);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">private final class BinderService extends IPowerManager.Stub {</span><br><span class="line"> ......</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">private final class LocalService extends PowerManagerInternal &#123;</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>onStart()中发布了BinderService,LocalService分别供其他进程,进程内其他服务调用,并将PowerManagerService加入到Watchdog监控中。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">public void onBootPhase(int phase) &#123;</span><br><span class="line"> synchronized (mLock) &#123;</span><br><span class="line"> if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) &#123;</span><br><span class="line"> ......</span><br><span class="line"> &#125; else if (phase == PHASE_BOOT_COMPLETED) &#123;</span><br><span class="line"> final long now = SystemClock.uptimeMillis();</span><br><span class="line"> // 设置mBootCompleted状态</span><br><span class="line"> mBootCompleted = true;</span><br><span class="line"> mDirty |= DIRTY_BOOT_COMPLETED;</span><br><span class="line"> // 更新userActivity及PowerState,后面分析</span><br><span class="line"> userActivityNoUpdateLocked(</span><br><span class="line"> now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);</span><br><span class="line"> updatePowerStateLocked();</span><br><span class="line"> // 执行mBootCompletedRunnables中的runnable方法</span><br><span class="line"> if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) &#123;</span><br><span class="line"> Slog.d(TAG, &quot;Posting &quot; + mBootCompletedRunnables.length + &quot; delayed runnables&quot;);</span><br><span class="line"> for (Runnable r : mBootCompletedRunnables) &#123;</span><br><span class="line"> BackgroundThread.getHandler().post(r);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> mBootCompletedRunnables = null;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>onBootPhase中主要设置mBootCompleted状态,更新PowerState状态,并执行mBootCompletedRunnables中的runnables方法(低电量模式会设置)。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">public void systemReady(IAppOpsService appOps) &#123;</span><br><span class="line"> synchronized (mLock) &#123;</span><br><span class="line"> mSystemReady = true;</span><br><span class="line"> // 获取AppOpsService</span><br><span class="line"> mAppOps = appOps;</span><br><span class="line"> // 获取DreamManager</span><br><span class="line"> mDreamManager = getLocalService(DreamManagerInternal.class);</span><br><span class="line"> // 获取DisplayManagerService</span><br><span class="line"> mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);</span><br><span class="line"> mPolicy = getLocalService(WindowManagerPolicy.class);</span><br><span class="line"> // 获取mBatteryService</span><br><span class="line"> mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);</span><br><span class="line"></span><br><span class="line"> PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);</span><br><span class="line"> // 获取屏幕默认,最大,最小亮度</span><br><span class="line"> mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();</span><br><span class="line"> mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();</span><br><span class="line"> mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();</span><br><span class="line"> // 获取SensorManager</span><br><span class="line"> SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());</span><br><span class="line"></span><br><span class="line"> mBatteryStats = BatteryStatsService.getService();</span><br><span class="line"> // 创建Notifier对象,用于广播power state的变化</span><br><span class="line"> mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,</span><br><span class="line"> mAppOps, createSuspendBlockerLocked(&quot;PowerManagerService.Broadcasts&quot;),</span><br><span class="line"> mPolicy);</span><br><span class="line"> // 无线充电检测</span><br><span class="line"> mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,</span><br><span class="line"> createSuspendBlockerLocked(&quot;PowerManagerService.WirelessChargerDetector&quot;),</span><br><span class="line"> mHandler);</span><br><span class="line"> // 监听设置的变化</span><br><span class="line"> mSettingsObserver = new SettingsObserver(mHandler);</span><br><span class="line"></span><br><span class="line"> mLightsManager = getLocalService(LightsManager.class);</span><br><span class="line"> mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);</span><br><span class="line"></span><br><span class="line"> // Initialize display power management.</span><br><span class="line"> mDisplayManagerInternal.initPowerManagement(</span><br><span class="line"> mDisplayPowerCallbacks, mHandler, sensorManager);</span><br><span class="line"></span><br><span class="line"> // Register for settings changes.</span><br><span class="line"> final ContentResolver resolver = mContext.getContentResolver();</span><br><span class="line"> resolver.registerContentObserver(Settings.Secure.getUriFor(</span><br><span class="line"> Settings.Secure.SCREENSAVER_ENABLED),</span><br><span class="line"> ......</span><br><span class="line"> IVrManager vrManager =</span><br><span class="line"> (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);</span><br><span class="line"> try &#123;</span><br><span class="line"> vrManager.registerListener(mVrStateCallbacks);</span><br><span class="line"> &#125; catch (RemoteException e) &#123;</span><br><span class="line"> Slog.e(TAG, &quot;Failed to register VR mode state listener: &quot; + e);</span><br><span class="line"> &#125;</span><br><span class="line"> // 读取配置</span><br><span class="line"> readConfigurationLocked();</span><br><span class="line"> updateSettingsLocked();</span><br><span class="line"> mDirty |= DIRTY_BATTERY_STATE;</span><br><span class="line"> updatePowerStateLocked();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // Register for broadcasts from other components of the system.</span><br><span class="line"> IntentFilter filter = new IntentFilter();</span><br><span class="line"> filter.addAction(Intent.ACTION_BATTERY_CHANGED);</span><br><span class="line"> filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);</span><br><span class="line"> mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);</span><br><span class="line"></span><br><span class="line"> filter = new IntentFilter();</span><br><span class="line"> filter.addAction(Intent.ACTION_DREAMING_STARTED);</span><br><span class="line"> filter.addAction(Intent.ACTION_DREAMING_STOPPED);</span><br><span class="line"> mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);</span><br><span class="line"></span><br><span class="line"> filter = new IntentFilter();</span><br><span class="line"> filter.addAction(Intent.ACTION_USER_SWITCHED);</span><br><span class="line"> mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);</span><br><span class="line"></span><br><span class="line"> filter = new IntentFilter();</span><br><span class="line"> filter.addAction(Intent.ACTION_DOCK_EVENT);</span><br><span class="line"> mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="userActivity"><a href="#userActivity" class="headerlink" title="userActivity"></a>userActivity</h1><p>userActivity是定义在PowerManager中的SystemApi,用户向PowerManagerService报告用户活动,以更新PowerManagerService内部时间/状态值,推迟系统休眠的时间。下面首先来看userActivity的定义。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/core/java/android/os/PowerManager.java</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * User activity event type: Unspecified event type.</span><br><span class="line"> */</span><br><span class="line">public static final int USER_ACTIVITY_EVENT_OTHER = 0;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * User activity event type: Button or key pressed or released.</span><br><span class="line"> */</span><br><span class="line">public static final int USER_ACTIVITY_EVENT_BUTTON = 1;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * User activity event type: Touch down, move or up.</span><br><span class="line"> */</span><br><span class="line">public static final int USER_ACTIVITY_EVENT_TOUCH = 2;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * User activity event type: Accessibility taking action on behalf of user.</span><br><span class="line"> */</span><br><span class="line">public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3;</span><br><span class="line"></span><br><span class="line">@SystemApi</span><br><span class="line">public void userActivity(long when, int event, int flags) &#123;</span><br><span class="line"> try &#123;</span><br><span class="line"> mService.userActivity(when, event, flags);</span><br><span class="line"> &#125; catch (RemoteException e) &#123;</span><br><span class="line"> throw e.rethrowFromSystemServer();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">private final class BinderService extends IPowerManager.Stub &#123;</span><br><span class="line"> ......</span><br><span class="line"> public void userActivity(long eventTime, int event, int flags) &#123;</span><br><span class="line"> final long now = SystemClock.uptimeMillis();</span><br><span class="line"> ......</span><br><span class="line"></span><br><span class="line"> if (eventTime &gt; now) &#123;</span><br><span class="line"> throw new IllegalArgumentException(&quot;event time must not be in the future&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> final int uid = Binder.getCallingUid();</span><br><span class="line"> final long ident = Binder.clearCallingIdentity();</span><br><span class="line"> try &#123;</span><br><span class="line"> userActivityInternal(eventTime, event, flags, uid);</span><br><span class="line"> &#125; finally &#123;</span><br><span class="line"> Binder.restoreCallingIdentity(ident);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>PowerManager中userActivity请求调用服务端PowerManagerService BinderService的userActivity,即调用内部方法userActivityInternal。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">private void userActivityInternal(long eventTime, int event, int flags, int uid) &#123;</span><br><span class="line"> synchronized (mLock) &#123;</span><br><span class="line"> if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) &#123;</span><br><span class="line"> updatePowerStateLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>userActivityInternal中首先调用userActivityNoUpdateLocked更新相关数据及状态(***NoUpdateLocked仅仅更新内部状态并不采取任何操作),然后调用updatePowerStateLocked更新所有PowerState,下面分析userActivityNoUpdateLocked的实现,updatePowerStateLocked是PowerManagerService的核心方法,在最后进行分析。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) &#123;</span><br><span class="line"> // 如果发生时间是上一次休眠或唤醒前,或当前没有开机完成到systemReady,不采取操作直接返回</span><br><span class="line"> if (eventTime &lt; mLastSleepTime || eventTime &lt; mLastWakeTime</span><br><span class="line"> || !mBootCompleted || !mSystemReady) &#123;</span><br><span class="line"> return false;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> try &#123;</span><br><span class="line"> // 更新mLastInteractivePowerHintTime时间</span><br><span class="line"> if (eventTime &gt; mLastInteractivePowerHintTime) &#123;</span><br><span class="line"> powerHintInternal(POWER_HINT_INTERACTION, 0);</span><br><span class="line"> mLastInteractivePowerHintTime = eventTime;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 通过mNotifier通知BatteryStats UserActivity事件</span><br><span class="line"> mNotifier.onUserActivity(event, uid);</span><br><span class="line"></span><br><span class="line"> if (mUserInactiveOverrideFromWindowManager) &#123;</span><br><span class="line"> mUserInactiveOverrideFromWindowManager = false;</span><br><span class="line"> mOverriddenTimeout = -1;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 如果系统处于休眠状态,不进行处理</span><br><span class="line"> if (mWakefulness == WAKEFULNESS_ASLEEP</span><br><span class="line"> || mWakefulness == WAKEFULNESS_DOZING</span><br><span class="line"> || (flags &amp; PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) &#123;</span><br><span class="line"> return false;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 根据flag是否在已变暗的情况下是否重启活动超时更新mLastUserActivityTimeNoChangeLights或mLastUserActivityTime</span><br><span class="line"> // 并且设置mDirty DIRTY_USER_ACTIVITY</span><br><span class="line"> if ((flags &amp; PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) &#123;</span><br><span class="line"> if (eventTime &gt; mLastUserActivityTimeNoChangeLights</span><br><span class="line"> &amp;&amp; eventTime &gt; mLastUserActivityTime) &#123;</span><br><span class="line"> mLastUserActivityTimeNoChangeLights = eventTime;</span><br><span class="line"> mDirty |= DIRTY_USER_ACTIVITY;</span><br><span class="line"> return true;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> if (eventTime &gt; mLastUserActivityTime) &#123;</span><br><span class="line"> mLastUserActivityTime = eventTime;</span><br><span class="line"> mDirty |= DIRTY_USER_ACTIVITY;</span><br><span class="line"> return true;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; finally &#123;</span><br><span class="line"> Trace.traceEnd(Trace.TRACE_TAG_POWER);</span><br><span class="line"> &#125;</span><br><span class="line"> return false;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="gotoSleep"><a href="#gotoSleep" class="headerlink" title="gotoSleep"></a>gotoSleep</h1><p>gotoSleep在PowerManager中的定义如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/core/java/android/os/PowerManager.java</span><br><span class="line"></span><br><span class="line">public void goToSleep(long time) &#123;</span><br><span class="line"> goToSleep(time, GO_TO_SLEEP_REASON_APPLICATION, 0);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">public void goToSleep(long time, int reason, int flags) &#123;</span><br><span class="line"> try &#123;</span><br><span class="line"> mService.goToSleep(time, reason, flags);</span><br><span class="line"> &#125; catch (RemoteException e) &#123;</span><br><span class="line"> throw e.rethrowFromSystemServer();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>与userActivity一样,gotoSleep最终将调用到goToSleepInternal。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">private final class BinderService extends IPowerManager.Stub &#123;</span><br><span class="line"> ......</span><br><span class="line"> public void goToSleep(long eventTime, int reason, int flags) &#123;</span><br><span class="line"> if (eventTime &gt; SystemClock.uptimeMillis()) &#123;</span><br><span class="line"> throw new IllegalArgumentException(&quot;event time must not be in the future&quot;);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> mContext.enforceCallingOrSelfPermission(</span><br><span class="line"> android.Manifest.permission.DEVICE_POWER, null);</span><br><span class="line"></span><br><span class="line"> final int uid = Binder.getCallingUid();</span><br><span class="line"> final long ident = Binder.clearCallingIdentity();</span><br><span class="line"> try &#123;</span><br><span class="line"> goToSleepInternal(eventTime, reason, flags, uid);</span><br><span class="line"> &#125; finally &#123;</span><br><span class="line"> Binder.restoreCallingIdentity(ident);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">private void goToSleepInternal(long eventTime, int reason, int flags, int uid) &#123;</span><br><span class="line"> synchronized (mLock) &#123;</span><br><span class="line"> if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) &#123;</span><br><span class="line"> updatePowerStateLocked();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>goToSleepInternal中将执行goToSleepNoUpdateLocked更新内部状态,同样在updatePowerStateLocked中更新PowerState的操作。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java</span><br><span class="line"></span><br><span class="line">private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) &#123;</span><br><span class="line"> // 当不处于awake状态或未开机systemReady,不处理</span><br><span class="line"> if (eventTime &lt; mLastWakeTime</span><br><span class="line"> || mWakefulness == WAKEFULNESS_ASLEEP</span><br><span class="line"> || mWakefulness == WAKEFULNESS_DOZING</span><br><span class="line"> || !mBootCompleted || !mSystemReady) &#123;</span><br><span class="line"> return false;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> try &#123;</span><br><span class="line"> ......</span><br><span class="line"> // 更新mLastSleepTime时间,设置DIRTY_WAKEFULNESS标志位</span><br><span class="line"> mLastSleepTime = eventTime;</span><br><span class="line"> mSandmanSummoned = true;</span><br><span class="line"> setWakefulnessLocked(WAKEFULNESS_DOZING, reason);</span><br><span class="line"></span><br><span class="line"> // Report the number of wake locks that will be cleared by going to sleep.</span><br><span class="line"> int numWakeLocksCleared = 0;</span><br><span class="line"> final int numWakeLocks = mWakeLocks.size();</span><br><span class="line"> for (int i = 0; i &lt; numWakeLocks; i++) &#123;</span><br><span class="line"> final WakeLock wakeLock = mWakeLocks.get(i);</span><br><span class="line"> switch (wakeLock.mFlags &amp; PowerManager.WAKE_LOCK_LEVEL_MASK) &#123;</span><br><span class="line"> case PowerManager.FULL_WAKE_LOCK:</span><br><span class="line"> case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:</span><br><span class="line"> case PowerManager.SCREEN_DIM_WAKE_LOCK:</span><br><span class="line"> numWakeLocksCleared += 1;</span><br><span class="line"> break;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // Skip dozing if requested.</span><br><span class="line"> if ((flags &amp; PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) &#123;</span><br><span class="line"> reallyGoToSleepNoUpdateLocked(eventTime, uid);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; finally &#123;</span><br><span class="line"> Trace.traceEnd(Trace.TRACE_TAG_POWER);</span><br><span class="line"> &#125;</span><br><span class="line"> return true;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>goToSleepNoUpdateLocked中更新mLastSleepTime,mWakefulness,mDirty状态。</p>
</content>
<summary type="html">
<blockquote>
<p>PowerManagerService提供Android系统的电源管理服务,主要功能是控制系统待机状态,屏幕显示,亮度调节,光线/距离传感器的控制等。</p>
<p>相关代码在以下文件中:<br>frameworks/base/services/j
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power Management" scheme="http://robinheztto.com/tags/Power-Management/"/>
<category term="PowerManagerService" scheme="http://robinheztto.com/tags/PowerManagerService/"/>
</entry>
<entry>
<title>Android电源管理系列之Wakelock</title>
<link href="http://robinheztto.com/2017/06/01/android-power-wakelock/"/>
<id>http://robinheztto.com/2017/06/01/android-power-wakelock/</id>
<published>2017-06-01T03:19:20.000Z</published>
<updated>2018-06-24T16:24:25.000Z</updated>
<content type="html"><blockquote>
<p>wakelocks最初来源于Android在linux kernel上的一个补丁集,旨在允许用户空间的应用能够通过持有Wakelock来阻止系统进入低功耗模式。</p>
<p>相关代码在以下文件中:<br>kernel/msm-4.4/kernel/power/wakelock.c<br>kernel/msm-4.4/kernel/power/main.c</p>
</blockquote>
<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>早期,为了适用移动设备的使用特性,Google在Linux的基础上为Android设计了一套新的电源管理机制 wakelocks,early_suspend。但由于此机制定义了Android自己的休眠接口,修改了Linux原生的susupend流程,导致在合入此patch的问题上Android和Linux内核开发者有<a href="http://lwn.net/Articles/318611/" target="_blank" rel="external">争论</a>。<br>直到kernel推出wakeup events framework,Android在wakeup events framework上重新修改了电源管理机制,弃用了之前的early_suspend机制,底层基于wakeup source重新实现了wakelocks(Android上层的Wakelock保留了原来的使用方式),其实就是将kernel中的wakeup source开放到用户空间。</p>
<p>新旧wakelock的对比如下(用户空间的使用方式一致,内核空间实现机制不同):</p>
<table>
<thead>
<tr>
<th></th>
<th>uesr space</th>
<th>kernel space</th>
</tr>
</thead>
<tbody>
<tr>
<td>old wakelock</td>
<td>写/sys/power/wake_lock阻止系统进入suspend,写/sys/power/wake_unlock允许suspend</td>
<td>lock在suspend的流程中加锁,阻止suspend,unlock移除该锁。</td>
</tr>
<tr>
<td>new wakelock</td>
<td>写/sys/power/wake_lock阻止系统进入suspend,写/sys/power/wake_unlock允许suspend</td>
<td>基于wakeup event framework的wakeup source实现,lock即active一个wakeup event,unlock deactive一个wakeup event。</td>
</tr>
</tbody>
</table>
<h1 id="Android-Wakelock"><a href="#Android-Wakelock" class="headerlink" title="Android Wakelock"></a>Android Wakelock</h1><p>在Android App中唤醒锁的使用如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">权限申明:</span><br><span class="line">&lt;uses-permission android:name=&quot;android.permission.WAKE_LOCK&quot; /&gt;</span><br><span class="line">&lt;uses-permission android:name=&quot;android.permission.DEVICE_POWER&quot;/&gt;</span><br><span class="line"></span><br><span class="line">代码使用:</span><br><span class="line">PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);</span><br><span class="line">PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, &quot;My Tag&quot;);</span><br><span class="line">wl.acquire(); //acquire时尽量申明timeout时间</span><br><span class="line">//......</span><br><span class="line">wl.release();</span><br></pre></td></tr></table></figure></p>
<p>在应用程序中使用WakeLock时必须申明权限,acquire请求唤醒锁时尽量设置timeout时间释放WakeLock,以避免长时间持有WakeLock导致系统无法休眠。</p>
<p>唤醒锁的类型:</p>
<table>
<thead>
<tr>
<th>Flag</th>
<th>CPU</th>
<th>Screen</th>
<th>Keyboard</th>
</tr>
</thead>
<tbody>
<tr>
<td>PARTIAL_WAKE_LOCK</td>
<td>on</td>
<td>off</td>
<td>off</td>
</tr>
<tr>
<td>SCREEN_DIM_WAKE_LOCK</td>
<td>on</td>
<td>Dim</td>
<td>off</td>
</tr>
<tr>
<td>SCREEN_BRIGHT_WAKE_LOCK</td>
<td>on</td>
<td>Bright</td>
<td>off</td>
</tr>
<tr>
<td>FULL_WAKE_LOCK</td>
<td>on</td>
<td>Bright</td>
<td>on</td>
</tr>
</tbody>
</table>
<p>如果是PARTIAL_WAKE_LOCK,无论屏幕的状态或是按下电源键, CPU都将正常工作。如果是其它的唤醒锁,设备会在用户按下电源钮后停止工作进入休眠状态。以上四种锁,除了PARTIAL_WAKE_LOCK,其余的锁在API level 17已经被deprecated了。</p>
<h1 id="Kernel-Wakelock"><a href="#Kernel-Wakelock" class="headerlink" title="Kernel Wakelock"></a>Kernel Wakelock</h1><p>如下图(来自<a href="http://www.wowotech.net" target="_blank" rel="external">蜗窝科技</a>)所示,PM core通过main模块向用户空间提供操作接口,即向用户空间暴露/sys/power/wake_lock与/sys/power/wake_unlock两个sysfs文件,PM core中的wakelock模块依赖于wakeup events framework提供的wakeup source机制实现,同时对用户空间的wakeup source(wakelock)提供支持。</p>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/android-power-wakelocks.jpeg?raw=true" alt="wakelocks"><br></div>
<p>下面首先来看Kernenl中的wakelock实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/wakelock.c</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line"> * kernel/power/wakelock.c</span><br><span class="line"> *</span><br><span class="line"> * User space wakeup sources support.</span><br><span class="line"> *</span><br><span class="line"> * Copyright (C) 2012 Rafael J. Wysocki &lt;[email protected]&gt;</span><br><span class="line"> *</span><br><span class="line"> * This code is based on the analogous interface allowing user space to</span><br><span class="line"> * manipulate wakelocks on Android.</span><br><span class="line"> */</span><br><span class="line"></span><br><span class="line">struct wakelock &#123;</span><br><span class="line"> char *name; // 该wakelock对应的name</span><br><span class="line"> struct rb_node node; // 红黑树节点,用于存储该wakelock</span><br><span class="line"> struct wakeup_source ws; // 该wakelock对应的wakeup source</span><br><span class="line">#ifdef CONFIG_PM_WAKELOCKS_GC</span><br><span class="line"> struct list_head lru; // 用于wakelock的回收机制</span><br><span class="line">#endif</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>通过注释信息可以知道,Kernenl中的wakelock是对用户空间wakelock支持的实现,以允许在用户空间操作wakeup source,创建Kerne wakelock的即在指定的wakeup source上activate一个wakeup event,注销wakelock的本质是deactivate wakeup event,下面从读写/sys/power/wake_lock和/sys/power/wake_unlock两个sysfs文件来详细分析该流程。</p>
<h2 id="读写wake-lock"><a href="#读写wake-lock" class="headerlink" title="读写wake_lock"></a>读写wake_lock</h2><p>/sys/power/wake_lock的读写方法定义如下,/sys/power/wake_lock的写方法直接调用pm_wake_lock(),读方法直接调用pm_show_wakelocks()。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/main.c</span><br><span class="line"></span><br><span class="line">static ssize_t wake_lock_show(struct kobject *kobj,</span><br><span class="line"> struct kobj_attribute *attr,</span><br><span class="line"> char *buf)</span><br><span class="line">&#123;</span><br><span class="line"> return pm_show_wakelocks(buf, true);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static ssize_t wake_lock_store(struct kobject *kobj,</span><br><span class="line"> struct kobj_attribute *attr,</span><br><span class="line"> const char *buf, size_t n)</span><br><span class="line">&#123;</span><br><span class="line"> int error = pm_wake_lock(buf);</span><br><span class="line"> return error ? error : n;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">power_attr(wake_lock);</span><br></pre></td></tr></table></figure></p>
<p>pm_wake_lock()与pm_show_wakelocks()都在wakelock.c中定义,先看pm_wake_lock()的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/wakelock.c</span><br><span class="line"></span><br><span class="line">int pm_wake_lock(const char *buf)</span><br><span class="line">&#123;</span><br><span class="line"> const char *str = buf;</span><br><span class="line"> struct wakelock *wl;</span><br><span class="line"> u64 timeout_ns = 0;</span><br><span class="line"> size_t len;</span><br><span class="line"> int ret = 0;</span><br><span class="line"></span><br><span class="line"> // 检查当前进程是否具备阻止系统suspend的权限</span><br><span class="line"> if (!capable(CAP_BLOCK_SUSPEND))</span><br><span class="line"> return -EPERM;</span><br><span class="line"> // 解析字符串,timeout_ns保存timeout值</span><br><span class="line"> while (*str &amp;&amp; !isspace(*str))</span><br><span class="line"> str++;</span><br><span class="line"></span><br><span class="line"> len = str - buf;</span><br><span class="line"> if (!len)</span><br><span class="line"> return -EINVAL;</span><br><span class="line"></span><br><span class="line"> if (*str &amp;&amp; *str != &apos;\n&apos;) &#123;</span><br><span class="line"> /* Find out if there&apos;s a valid timeout string appended. */</span><br><span class="line"> ret = kstrtou64(skip_spaces(str), 10, &amp;timeout_ns);</span><br><span class="line"> if (ret)</span><br><span class="line"> return -EINVAL;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> mutex_lock(&amp;wakelocks_lock);</span><br><span class="line"> // 从RB tree中查找buf名字对应的wakelock,如果找到则返回,没找到则新建wakelock对象并返回</span><br><span class="line"> wl = wakelock_lookup_add(buf, len, true);</span><br><span class="line"> if (IS_ERR(wl)) &#123;</span><br><span class="line"> ret = PTR_ERR(wl);</span><br><span class="line"> goto out;</span><br><span class="line"> &#125;</span><br><span class="line"> // 如果指定timeout值,以wakelock的wakeup source指针为参数,调用__pm_wakeup_event接口,上报一个具有时限的wakeup events;</span><br><span class="line"> // 如果没有指定timeout值,调用__pm_stay_awake,上报一个没有时限的wakeup event。</span><br><span class="line"> if (timeout_ns) &#123;</span><br><span class="line"> u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;</span><br><span class="line"> do_div(timeout_ms, NSEC_PER_MSEC);</span><br><span class="line"> __pm_wakeup_event(&amp;wl-&gt;ws, timeout_ms);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> __pm_stay_awake(&amp;wl-&gt;ws);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> wakelocks_lru_most_recent(wl);</span><br><span class="line"></span><br><span class="line"> out:</span><br><span class="line"> mutex_unlock(&amp;wakelocks_lock);</span><br><span class="line"> return ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>继续看内部接口wakelock_lookup_add的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/wakelock.c</span><br><span class="line"></span><br><span class="line">static struct wakelock *wakelock_lookup_add(const char *name, size_t len,</span><br><span class="line"> bool add_if_not_found)</span><br><span class="line">&#123;</span><br><span class="line"> struct rb_node **node = &amp;wakelocks_tree.rb_node;</span><br><span class="line"> struct rb_node *parent = *node;</span><br><span class="line"> struct wakelock *wl;</span><br><span class="line"></span><br><span class="line"> // 根据name查找红黑树上对应的wakelock</span><br><span class="line"> while (*node) &#123;</span><br><span class="line"> int diff;</span><br><span class="line"></span><br><span class="line"> parent = *node;</span><br><span class="line"> wl = rb_entry(*node, struct wakelock, node);</span><br><span class="line"> diff = strncmp(name, wl-&gt;name, len);</span><br><span class="line"> if (diff == 0) &#123;</span><br><span class="line"> if (wl-&gt;name[len])</span><br><span class="line"> diff = -1;</span><br><span class="line"> else</span><br><span class="line"> return wl;</span><br><span class="line"> &#125;</span><br><span class="line"> if (diff &lt; 0)</span><br><span class="line"> node = &amp;(*node)-&gt;rb_left;</span><br><span class="line"> else</span><br><span class="line"> node = &amp;(*node)-&gt;rb_right;</span><br><span class="line"> &#125;</span><br><span class="line"> if (!add_if_not_found)</span><br><span class="line"> return ERR_PTR(-EINVAL);</span><br><span class="line"></span><br><span class="line"> if (wakelocks_limit_exceeded())</span><br><span class="line"> return ERR_PTR(-ENOSPC);</span><br><span class="line"></span><br><span class="line"> // 没有找到,创建新的wakelock</span><br><span class="line"> wl = kzalloc(sizeof(*wl), GFP_KERNEL);</span><br><span class="line"> if (!wl)</span><br><span class="line"> return ERR_PTR(-ENOMEM);</span><br><span class="line"></span><br><span class="line"> wl-&gt;name = kstrndup(name, len, GFP_KERNEL);</span><br><span class="line"> if (!wl-&gt;name) &#123;</span><br><span class="line"> kfree(wl);</span><br><span class="line"> return ERR_PTR(-ENOMEM);</span><br><span class="line"> &#125;</span><br><span class="line"> wl-&gt;ws.name = wl-&gt;name;</span><br><span class="line"> // 将wakeup source添加到wakeup events framework中</span><br><span class="line"> wakeup_source_add(&amp;wl-&gt;ws);</span><br><span class="line"> // 将该wakelock添加到红黑树</span><br><span class="line"> rb_link_node(&amp;wl-&gt;node, parent, node);</span><br><span class="line"> rb_insert_color(&amp;wl-&gt;node, &amp;wakelocks_tree);</span><br><span class="line"> // 将新分配的wakeup添加到一个名称为wakelocks_lru_list的链表前端</span><br><span class="line"> wakelocks_lru_add(wl);</span><br><span class="line"> increment_wakelocks_number();</span><br><span class="line"> return wl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>下面继续看读wake_lock的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/wakelock.c</span><br><span class="line"></span><br><span class="line">ssize_t pm_show_wakelocks(char *buf, bool show_active)</span><br><span class="line">&#123;</span><br><span class="line"> struct rb_node *node;</span><br><span class="line"> struct wakelock *wl;</span><br><span class="line"> char *str = buf;</span><br><span class="line"> char *end = buf + PAGE_SIZE;</span><br><span class="line"></span><br><span class="line"> mutex_lock(&amp;wakelocks_lock);</span><br><span class="line"> // 遍历红黑树,拿到wakelock指针,将该wakelock的名字添加在buf</span><br><span class="line"> for (node = rb_first(&amp;wakelocks_tree); node; node = rb_next(node)) &#123;</span><br><span class="line"> wl = rb_entry(node, struct wakelock, node);</span><br><span class="line"> // 判断其中的wakeup source的active变量与show_active是否相符</span><br><span class="line"> if (wl-&gt;ws.active == show_active)</span><br><span class="line"> str += scnprintf(str, end - str, &quot;%s &quot;, wl-&gt;name);</span><br><span class="line"> &#125;</span><br><span class="line"> if (str &gt; buf)</span><br><span class="line"> str--;</span><br><span class="line"></span><br><span class="line"> str += scnprintf(str, end - str, &quot;\n&quot;);</span><br><span class="line"></span><br><span class="line"> mutex_unlock(&amp;wakelocks_lock);</span><br><span class="line"> return (str - buf);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="读写wake-unlock"><a href="#读写wake-unlock" class="headerlink" title="读写wake_unlock"></a>读写wake_unlock</h2><p>/sys/power/wake_unlock的读写方法定义如下,/sys/power/wake_unlock的写方法直接调用pm_wake_unlock(),读方法直接调用pm_show_wakelocks(),pm_show_wakelocks在上面已经分析。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/main.c</span><br><span class="line"></span><br><span class="line">static ssize_t wake_unlock_show(struct kobject *kobj,</span><br><span class="line"> struct kobj_attribute *attr,</span><br><span class="line"> char *buf)</span><br><span class="line">&#123;</span><br><span class="line"> return pm_show_wakelocks(buf, false);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static ssize_t wake_unlock_store(struct kobject *kobj,</span><br><span class="line"> struct kobj_attribute *attr,</span><br><span class="line"> const char *buf, size_t n)</span><br><span class="line">&#123;</span><br><span class="line"> int error = pm_wake_unlock(buf);</span><br><span class="line"> return error ? error : n;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">power_attr(wake_unlock);</span><br></pre></td></tr></table></figure></p>
<p>pm_wake_unlock()在wakelock.c中定义,下面看他的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/wakelock.c</span><br><span class="line"></span><br><span class="line">int pm_wake_unlock(const char *buf)</span><br><span class="line">&#123;</span><br><span class="line"> struct wakelock *wl;</span><br><span class="line"> size_t len;</span><br><span class="line"> int ret = 0;</span><br><span class="line"></span><br><span class="line"> // 检查当前进程是否具备阻止系统suspend的权限</span><br><span class="line"> if (!capable(CAP_BLOCK_SUSPEND))</span><br><span class="line"> return -EPERM;</span><br><span class="line"></span><br><span class="line"> // 解析字符串</span><br><span class="line"> len = strlen(buf);</span><br><span class="line"> if (!len)</span><br><span class="line"> return -EINVAL;</span><br><span class="line"></span><br><span class="line"> if (buf[len-1] == &apos;\n&apos;)</span><br><span class="line"> len--;</span><br><span class="line"></span><br><span class="line"> if (!len)</span><br><span class="line"> return -EINVAL;</span><br><span class="line"></span><br><span class="line"> mutex_lock(&amp;wakelocks_lock);</span><br><span class="line"> // 根据name在RB树中查找是wakelock,没有则退出</span><br><span class="line"> wl = wakelock_lookup_add(buf, len, false);</span><br><span class="line"> if (IS_ERR(wl)) &#123;</span><br><span class="line"> ret = PTR_ERR(wl);</span><br><span class="line"> goto out;</span><br><span class="line"> &#125;</span><br><span class="line"> // 调用__pm_relax接口,deactive wakelock对应的wakeup source。</span><br><span class="line"> __pm_relax(&amp;wl-&gt;ws);</span><br><span class="line"> // 调用wakelocks_lru_most_recent接口,将盖wakelock移到wakelocks_lru_list链表的前端,并执行垃圾回收操作</span><br><span class="line"> wakelocks_lru_most_recent(wl);</span><br><span class="line"> wakelocks_gc();</span><br><span class="line"></span><br><span class="line"> out:</span><br><span class="line"> mutex_unlock(&amp;wakelocks_lock);</span><br><span class="line"> return ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</content>
<summary type="html">
<blockquote>
<p>wakelocks最初来源于Android在linux kernel上的一个补丁集,旨在允许用户空间的应用能够通过持有Wakelock来阻止系统进入低功耗模式。</p>
<p>相关代码在以下文件中:<br>kernel/msm-4.4/kernel
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power Management" scheme="http://robinheztto.com/tags/Power-Management/"/>
</entry>
<entry>
<title>Android电源管理系列之libsuspend</title>
<link href="http://robinheztto.com/2017/05/20/android-power-libsuspend/"/>
<id>http://robinheztto.com/2017/05/20/android-power-libsuspend/</id>
<published>2017-05-20T08:38:19.000Z</published>
<updated>2018-01-07T04:07:05.000Z</updated>
<content type="html"><blockquote>
<p>Android向上层提供了操作休眠相关的接口(即读写/sys/power/目录下文件),即libsuspend.so,<br>源码位于system/core/libsuspend下:<br>system/core/libsuspend<br>kernel/msm-4.4/kernel/power/suspend.c<br>kernel/msm-4.4/kernel/power/process.c<br>kernel/msm-4.4/kernel/power/console.c<br>kernel/msm-4.4/kernel/power/power.h<br>kernel/msm-4.4/include/linux/suspend.h<br>kernel-x.xx/drivers/misc/mediatek/base/power/spm_v2/mt_sleep.c</p>
</blockquote>
</content>
<summary type="html">
<blockquote>
<p>Android向上层提供了操作休眠相关的接口(即读写/sys/power/目录下文件),即libsuspend.so,<br>源码位于system/core/libsuspend下:<br>system/core/libsuspend<br>ker
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power Management" scheme="http://robinheztto.com/tags/Power-Management/"/>
</entry>
<entry>
<title>Android电源管理系列之Suspend</title>
<link href="http://robinheztto.com/2017/05/05/android-power-suspend/"/>
<id>http://robinheztto.com/2017/05/05/android-power-suspend/</id>
<published>2017-05-05T07:46:56.000Z</published>
<updated>2018-01-07T04:07:05.000Z</updated>
<content type="html"><blockquote>
<p>kernel/msm-4.4/kernel/power/main.c<br>kernel/msm-4.4/kernel/power/suspend.c<br>kernel/msm-4.4/kernel/power/process.c<br>kernel/msm-4.4/kernel/power/console.c<br>kernel/msm-4.4/kernel/power/power.h<br>kernel/msm-4.4/include/linux/suspend.h<br>kernel-x.xx/drivers/misc/mediatek/base/power/spm_v2/mt_sleep.c</p>
</blockquote>
<p>Linux kernel提供Freeze,Standby,STR(Supend to RAM)三种Suspend机制,当用户空间向”/sys/power/state”文件分别写”freeze”,”standby”,”mem”时即触发对应的suspend流程。关于PM_SUSPEND的定义如下所示:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/include/linux/suspend.h</span><br><span class="line"></span><br><span class="line">#define PM_SUSPEND_ON ((__force suspend_state_t) 0)</span><br><span class="line">#define PM_SUSPEND_FREEZE ((__force suspend_state_t) 1)</span><br><span class="line">#define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2)</span><br><span class="line">#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)</span><br><span class="line">#define PM_SUSPEND_MIN PM_SUSPEND_FREEZE</span><br><span class="line">#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)</span><br></pre></td></tr></table></figure></p>
<p>下面先从/sys/power/下属性文件的创建开始分析。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/main.c</span><br><span class="line"></span><br><span class="line">static int __init pm_init(void)</span><br><span class="line">&#123;</span><br><span class="line"> int error = pm_start_workqueue();</span><br><span class="line"> if (error)</span><br><span class="line"> return error;</span><br><span class="line"> hibernate_image_size_init();</span><br><span class="line"> hibernate_reserved_size_init();</span><br><span class="line"> power_kobj = kobject_create_and_add(&quot;power&quot;, NULL);</span><br><span class="line"> if (!power_kobj)</span><br><span class="line"> return -ENOMEM;</span><br><span class="line"> error = sysfs_create_group(power_kobj, &amp;attr_group);</span><br><span class="line"> if (error)</span><br><span class="line"> return error;</span><br><span class="line"> pm_print_times_init();</span><br><span class="line"> return pm_autosleep_init();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">core_initcall(pm_init);</span><br></pre></td></tr></table></figure></p>
<p>pm_init中创建了/sys/power目录,并且根据attr_group的定义创建对应的属性文件,attr_group的定义如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/main.c</span><br><span class="line"></span><br><span class="line">static struct attribute * g[] = &#123;</span><br><span class="line"> &amp;state_attr.attr,</span><br><span class="line">#ifdef CONFIG_PM_TRACE</span><br><span class="line"> &amp;pm_trace_attr.attr,</span><br><span class="line"> &amp;pm_trace_dev_match_attr.attr,</span><br><span class="line">#endif</span><br><span class="line">#ifdef CONFIG_PM_SLEEP</span><br><span class="line"> &amp;pm_async_attr.attr,</span><br><span class="line"> &amp;wakeup_count_attr.attr,</span><br><span class="line">#ifdef CONFIG_PM_AUTOSLEEP</span><br><span class="line"> &amp;autosleep_attr.attr,</span><br><span class="line">#endif</span><br><span class="line">#ifdef CONFIG_PM_WAKELOCKS</span><br><span class="line"> &amp;wake_lock_attr.attr,</span><br><span class="line"> &amp;wake_unlock_attr.attr,</span><br><span class="line">#endif</span><br><span class="line">#ifdef CONFIG_PM_DEBUG</span><br><span class="line"> &amp;pm_test_attr.attr,</span><br><span class="line">#endif</span><br><span class="line">#ifdef CONFIG_PM_SLEEP_DEBUG</span><br><span class="line"> &amp;pm_print_times_attr.attr,</span><br><span class="line"> &amp;pm_wakeup_irq_attr.attr,</span><br><span class="line">#endif</span><br><span class="line">#endif</span><br><span class="line">#ifdef CONFIG_FREEZER</span><br><span class="line"> &amp;pm_freeze_timeout_attr.attr,</span><br><span class="line">#endif</span><br><span class="line"> NULL,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">static struct attribute_group attr_group = &#123;</span><br><span class="line"> .attrs = g,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>attribute_group中定义了state_attr,pm_async_attr,wakeup_count_attr,wake_lock_attr,wake_unlock_attr等attribute,对应生成/sys/power/state,/sys/power/pm_async,/sys/power/wakeup_count,/sys/power/wake_lock,/sys/power/wake_unlock等属性文件。state_attr等attribute的show,sotre通过宏power_attr来定义的。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/power.h</span><br><span class="line"></span><br><span class="line">#define power_attr(_name) \</span><br><span class="line">static struct kobj_attribute _name##_attr = &#123; \</span><br><span class="line"> .attr = &#123; \</span><br><span class="line"> .name = __stringify(_name), \</span><br><span class="line"> .mode = 0644, \</span><br><span class="line"> &#125;, \</span><br><span class="line"> .show = _name##_show, \</span><br><span class="line"> .store = _name##_store, \</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/main.c</span><br><span class="line"></span><br><span class="line">power_attr(pm_async);</span><br><span class="line">power_attr(state);</span><br><span class="line">power_attr(wake_unlock);</span><br><span class="line">power_attr(wake_lock);</span><br><span class="line">power_attr(wakeup_count);</span><br><span class="line">......</span><br></pre></td></tr></table></figure>
<p>下面首先看/sys/power/state的读取方法state_show的实现,即显平台所支持的Suspend机制(通过<code>cat /sys/power/state</code>可查询)。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/main.c</span><br><span class="line"></span><br><span class="line">const char *pm_states[PM_SUSPEND_MAX];</span><br><span class="line"></span><br><span class="line">static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,</span><br><span class="line"> char *buf)</span><br><span class="line">&#123;</span><br><span class="line"> char *s = buf;</span><br><span class="line">#ifdef CONFIG_SUSPEND</span><br><span class="line"> suspend_state_t i;</span><br><span class="line"></span><br><span class="line"> for (i = PM_SUSPEND_MIN; i &lt; PM_SUSPEND_MAX; i++)</span><br><span class="line"> if (pm_states[i])</span><br><span class="line"> s += sprintf(s,&quot;%s &quot;, pm_states[i]);</span><br><span class="line"></span><br><span class="line">#endif</span><br><span class="line"> if (hibernation_available())</span><br><span class="line"> s += sprintf(s, &quot;disk &quot;);</span><br><span class="line"> if (s != buf)</span><br><span class="line"> /* convert the last space to a newline */</span><br><span class="line"> *(s-1) = &apos;\n&apos;;</span><br><span class="line"> return (s - buf);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>state_show实际上显示的是pm_states中的值,pm_states时在suspend_set_ops中初始化赋值的,后面再详细描述。继续看state_store即suspend的流程。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/main.c</span><br><span class="line"></span><br><span class="line">static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,</span><br><span class="line"> const char *buf, size_t n)</span><br><span class="line">&#123;</span><br><span class="line"> suspend_state_t state;</span><br><span class="line"> int error;</span><br><span class="line"></span><br><span class="line"> error = pm_autosleep_lock();</span><br><span class="line"> if (error)</span><br><span class="line"> return error;</span><br><span class="line"></span><br><span class="line"> if (pm_autosleep_state() &gt; PM_SUSPEND_ON) &#123;</span><br><span class="line"> error = -EBUSY;</span><br><span class="line"> goto out;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> state = decode_state(buf, n);</span><br><span class="line"> if (state &lt; PM_SUSPEND_MAX)</span><br><span class="line"> error = pm_suspend(state);</span><br><span class="line"> else if (state == PM_SUSPEND_MAX)</span><br><span class="line"> error = hibernate();</span><br><span class="line"> else</span><br><span class="line"> error = -EINVAL;</span><br><span class="line"></span><br><span class="line"> out:</span><br><span class="line"> pm_autosleep_unlock();</span><br><span class="line"> return error ? error : n;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">power_attr(state);</span><br></pre></td></tr></table></figure></p>
<p>state_store中首先解析从用户空间传入的buffer(freeze、standby or mem),转换成state参数,然后调用pm_suspend()继续处理。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/suspend.c</span><br><span class="line"></span><br><span class="line">int pm_suspend(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> int error;</span><br><span class="line"></span><br><span class="line"> if (state &lt;= PM_SUSPEND_ON || state &gt;= PM_SUSPEND_MAX)</span><br><span class="line"> return -EINVAL;</span><br><span class="line"></span><br><span class="line"> pm_suspend_marker(&quot;entry&quot;);</span><br><span class="line"> error = enter_state(state);</span><br><span class="line"> if (error) &#123;</span><br><span class="line"> suspend_stats.fail++;</span><br><span class="line"> dpm_save_failed_errno(error);</span><br><span class="line"> &#125; else &#123;</span><br><span class="line"> suspend_stats.success++;</span><br><span class="line"> &#125;</span><br><span class="line"> pm_suspend_marker(&quot;exit&quot;);</span><br><span class="line"> return error;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>pm_suspend中首先对参数state进行判断是否合法,然后继续调用enter_state。由pm_suspend_marker可以看到,”entry”与”exit”都是在pm_suspend中,enter_state函数进入休眠直到唤醒时才返回。另外debug时,可根据pm_suspend_marker确定进入与退出suspend的时间,如下。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/suspend.c</span><br><span class="line"></span><br><span class="line">static void pm_suspend_marker(char *annotation)</span><br><span class="line">&#123;</span><br><span class="line"> struct timespec ts;</span><br><span class="line"> struct rtc_time tm;</span><br><span class="line"></span><br><span class="line"> getnstimeofday(&amp;ts);</span><br><span class="line"> rtc_time_to_tm(ts.tv_sec, &amp;tm);</span><br><span class="line"> pr_info(&quot;PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n&quot;,</span><br><span class="line"> annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,</span><br><span class="line"> tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>继续看enter_state的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/suspend.c</span><br><span class="line"></span><br><span class="line">static int enter_state(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> int error;</span><br><span class="line"></span><br><span class="line"> trace_suspend_resume(TPS(&quot;suspend_enter&quot;), state, true);</span><br><span class="line"> if (state == PM_SUSPEND_FREEZE) &#123;</span><br><span class="line">#ifdef CONFIG_PM_DEBUG</span><br><span class="line"> if (pm_test_level != TEST_NONE &amp;&amp; pm_test_level &lt;= TEST_CPUS) &#123;</span><br><span class="line"> pr_warning(&quot;PM: Unsupported test mode for suspend to idle,&quot;</span><br><span class="line"> &quot;please choose none/freezer/devices/platform.\n&quot;);</span><br><span class="line"> return -EAGAIN;</span><br><span class="line"> &#125;</span><br><span class="line">#endif</span><br><span class="line"> // 判断是否支持请求的状态state</span><br><span class="line"> &#125; else if (!valid_state(state)) &#123;</span><br><span class="line"> return -EINVAL;</span><br><span class="line"> &#125;</span><br><span class="line"> // 互斥锁,只允许同时处理一个suspend流程</span><br><span class="line"> if (!mutex_trylock(&amp;pm_mutex))</span><br><span class="line"> return -EBUSY;</span><br><span class="line"> // 请求进入freeze,调用freeze_begin流程</span><br><span class="line"> if (state == PM_SUSPEND_FREEZE)</span><br><span class="line"> freeze_begin();</span><br><span class="line"></span><br><span class="line"> // state为standby或mem则进入一下流程处理,首先sync文件系统</span><br><span class="line">#ifndef CONFIG_SUSPEND_SKIP_SYNC</span><br><span class="line"> trace_suspend_resume(TPS(&quot;sync_filesystems&quot;), 0, true);</span><br><span class="line"> printk(KERN_INFO &quot;PM: Syncing filesystems ... &quot;);</span><br><span class="line"> sys_sync();</span><br><span class="line"> printk(&quot;done.\n&quot;);</span><br><span class="line"> trace_suspend_resume(TPS(&quot;sync_filesystems&quot;), 0, false);</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> pr_debug(&quot;PM: Preparing system for sleep (%s)\n&quot;, pm_states[state]);</span><br><span class="line"> pm_suspend_clear_flags();</span><br><span class="line"> // 调用suspend_prepare进行suspend前的准备工作</span><br><span class="line"> error = suspend_prepare(state);</span><br><span class="line"> if (error)</span><br><span class="line"> goto Unlock;</span><br><span class="line"></span><br><span class="line"> if (suspend_test(TEST_FREEZER))</span><br><span class="line"> goto Finish;</span><br><span class="line"></span><br><span class="line"> trace_suspend_resume(TPS(&quot;suspend_enter&quot;), state, false);</span><br><span class="line"> pr_debug(&quot;PM: Suspending system (%s)\n&quot;, pm_states[state]);</span><br><span class="line"> pm_restrict_gfp_mask();</span><br><span class="line"> // 进入suspend流程</span><br><span class="line"> error = suspend_devices_and_enter(state);</span><br><span class="line"> pm_restore_gfp_mask();</span><br><span class="line"></span><br><span class="line"> Finish:</span><br><span class="line"> pr_debug(&quot;PM: Finishing wakeup.\n&quot;);</span><br><span class="line"> // 退出suspend,恢复suspend前的状态</span><br><span class="line"> suspend_finish();</span><br><span class="line"> Unlock:</span><br><span class="line"> mutex_unlock(&amp;pm_mutex);</span><br><span class="line"> return error;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>enter_state中根据state判断,如果是freeze,则进入freeze_begin()处理,如果是standby或mem,则首先同步文件系统,然后调用suspend_prepare进行suspend前的准备工作,最后在suspend_devices_and_enter中进入suspend,当系统唤醒时,在suspend_finish中进行恢复操作。下面详细分析该流程,首先看valid_state的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/include/linux/suspend.h</span><br><span class="line"></span><br><span class="line">struct platform_suspend_ops &#123;</span><br><span class="line"> int (*valid)(suspend_state_t state);</span><br><span class="line"> int (*begin)(suspend_state_t state);</span><br><span class="line"> int (*prepare)(void);</span><br><span class="line"> int (*prepare_late)(void);</span><br><span class="line"> int (*enter)(suspend_state_t state);</span><br><span class="line"> void (*wake)(void);</span><br><span class="line"> void (*finish)(void);</span><br><span class="line"> bool (*suspend_again)(void);</span><br><span class="line"> void (*end)(void);</span><br><span class="line"> void (*recover)(void);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/suspend.c</span><br><span class="line"></span><br><span class="line">static const struct platform_suspend_ops *suspend_ops;</span><br><span class="line"></span><br><span class="line">static bool valid_state(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> /*</span><br><span class="line"> * PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level</span><br><span class="line"> * support and need to be valid to the low level</span><br><span class="line"> * implementation, no valid callback implies that none are valid.</span><br><span class="line"> */</span><br><span class="line"> return suspend_ops &amp;&amp; suspend_ops-&gt;valid &amp;&amp; suspend_ops-&gt;valid(state);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>valid_state中调用的是suspend_ops-&gt;valid,(注释可以看到PM_SUSPEND_STANDBY和PM_SUSPEND_MEM是需要底层支持),即在平台代码中实现。下面以MTK平台为例,看platform_suspend_ops的实现。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel-x.xx/drivers/misc/mediatek/base/power/spm_v2/mt_sleep.c</span><br><span class="line"></span><br><span class="line">static int slp_suspend_ops_valid(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> return state == PM_SUSPEND_MEM;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static int slp_suspend_ops_begin(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> /* legacy log */</span><br><span class="line"> slp_notice(&quot;@@@@@@@@@@@@@@@@@@@@\tChip_pm_begin(%u)(%u)\t@@@@@@@@@@@@@@@@@@@@\n&quot;,</span><br><span class="line"> is_cpu_pdn(slp_spm_flags), is_infra_pdn(slp_spm_flags));</span><br><span class="line"></span><br><span class="line"> slp_wake_reason = WR_NONE;</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void __attribute__((weak)) mt_power_gs_dump_suspend(void)</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static int slp_suspend_ops_prepare(void)</span><br><span class="line">&#123;</span><br><span class="line"> /* legacy log */</span><br><span class="line"> slp_crit2(&quot;@@@@@@@@@@@@@@@@@@@@\tChip_pm_prepare\t@@@@@@@@@@@@@@@@@@@@\n&quot;);</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">#ifdef CONFIG_MTKPASR</span><br><span class="line">/* PASR/DPD Preliminary operations */</span><br><span class="line">static int slp_suspend_ops_prepare_late(void)</span><br><span class="line">&#123;</span><br><span class="line"> slp_notice(&quot;[%s]\n&quot;, __func__);</span><br><span class="line"> mtkpasr_phaseone_ops();</span><br><span class="line"> return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static void slp_suspend_ops_wake(void)</span><br><span class="line">&#123;</span><br><span class="line"> slp_notice(&quot;[%s]\n&quot;, __func__);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static int slp_suspend_ops_enter(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> ......</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static void slp_suspend_ops_finish(void)</span><br><span class="line">&#123;</span><br><span class="line"> /* legacy log */</span><br><span class="line"> slp_crit2(&quot;@@@@@@@@@@@@@@@@@@@@\tChip_pm_finish\t@@@@@@@@@@@@@@@@@@@@\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static void slp_suspend_ops_end(void)</span><br><span class="line">&#123;</span><br><span class="line"> /* legacy log */</span><br><span class="line"> slp_notice(&quot;@@@@@@@@@@@@@@@@@@@@\tChip_pm_end\t@@@@@@@@@@@@@@@@@@@@\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static const struct platform_suspend_ops slp_suspend_ops = &#123;</span><br><span class="line"> .valid = slp_suspend_ops_valid,</span><br><span class="line"> .begin = slp_suspend_ops_begin,</span><br><span class="line"> .prepare = slp_suspend_ops_prepare,</span><br><span class="line"> .enter = slp_suspend_ops_enter,</span><br><span class="line"> .finish = slp_suspend_ops_finish,</span><br><span class="line"> .end = slp_suspend_ops_end,</span><br><span class="line">#ifdef CONFIG_MTKPASR</span><br><span class="line"> .prepare_late = slp_suspend_ops_prepare_late,</span><br><span class="line"> .wake = slp_suspend_ops_wake,</span><br><span class="line">#endif</span><br><span class="line">&#125;;</span><br><span class="line">#endif</span><br></pre></td></tr></table></figure></p>
<p>mt_sleep.c中定义了platform_suspend_ops的实现,这里的slp_suspend_ops_valid支持的是PM_SUSPEND_MEM。接下来继续回到enter_state函数中分析suspend_prepare的流程。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/suspend.c</span><br><span class="line"></span><br><span class="line">static int suspend_prepare(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> int error;</span><br><span class="line"></span><br><span class="line"> // 检查是否支持该state,PM_SUSPEND_FREEZE或者有实现suspend_ops-&gt;enter</span><br><span class="line"> if (!sleep_state_supported(state))</span><br><span class="line"> return -EPERM;</span><br><span class="line"></span><br><span class="line"> // 将当前console切换到一个虚拟console并重定向内核的kmsg </span><br><span class="line"> pm_prepare_console();</span><br><span class="line"></span><br><span class="line"> // 发送PM_SUSPEND_PREPARE消息 </span><br><span class="line"> error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);</span><br><span class="line"> if (error)</span><br><span class="line"> goto Finish;</span><br><span class="line"></span><br><span class="line"> trace_suspend_resume(TPS(&quot;freeze_processes&quot;), 0, true);</span><br><span class="line"> // freeze用户空间进程和内核线程</span><br><span class="line"> error = suspend_freeze_processes();</span><br><span class="line"> trace_suspend_resume(TPS(&quot;freeze_processes&quot;), 0, false);</span><br><span class="line"> if (!error)</span><br><span class="line"> return 0;</span><br><span class="line"></span><br><span class="line"> suspend_stats.failed_freeze++;</span><br><span class="line"> dpm_save_failed_step(SUSPEND_FREEZE);</span><br><span class="line"> Finish:</span><br><span class="line"> // 如果freeze失败,则恢复console的操作</span><br><span class="line"> pm_notifier_call_chain(PM_POST_SUSPEND);</span><br><span class="line"> pm_restore_console();</span><br><span class="line"> return error;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>suspend_prepare主要是处理console并冻结用户进程与内核线程,在suspend_prepare准备工作之后,调用suspend_devices_and_enter开始进入suspend状态。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/suspend.c</span><br><span class="line"></span><br><span class="line">int suspend_devices_and_enter(suspend_state_t state)</span><br><span class="line">&#123;</span><br><span class="line"> int error;</span><br><span class="line"> bool wakeup = false;</span><br><span class="line"></span><br><span class="line"> // 再次检查是否支持该state,PM_SUSPEND_FREEZE或者有实现suspend_ops-&gt;enter</span><br><span class="line"> if (!sleep_state_supported(state))</span><br><span class="line"> return -ENOSYS;</span><br><span class="line"></span><br><span class="line"> //调用平台实现suspend_ops-&gt;begin()</span><br><span class="line"> error = platform_suspend_begin(state);</span><br><span class="line"> if (error)</span><br><span class="line"> goto Close;</span><br><span class="line"></span><br><span class="line"> //挂起console</span><br><span class="line"> suspend_console();</span><br><span class="line"> suspend_test_start();</span><br><span class="line"> //调用所有设备的-&gt;prepare和-&gt;suspend回调函数,注意suspend device可能失败,会跳至Recover_platform,执行recover操作(suspend_ops-&gt;recover)</span><br><span class="line"> error = dpm_suspend_start(PMSG_SUSPEND);</span><br><span class="line"> if (error) &#123;</span><br><span class="line"> pr_err(&quot;PM: Some devices failed to suspend, or early wake event detected\n&quot;);</span><br><span class="line"> log_suspend_abort_reason(&quot;Some devices failed to suspend, or early wake event detected&quot;);</span><br><span class="line"> goto Recover_platform;</span><br><span class="line"> &#125;</span><br><span class="line"> suspend_test_finish(&quot;suspend devices&quot;);</span><br><span class="line"> if (suspend_test(TEST_DEVICES))</span><br><span class="line"> goto Recover_platform;</span><br><span class="line"></span><br><span class="line"> do &#123;</span><br><span class="line"> // 最终,在suspend_enter中进入suspend状态</span><br><span class="line"> error = suspend_enter(state, &amp;wakeup);</span><br><span class="line"> &#125; while (!error &amp;&amp; !wakeup &amp;&amp; platform_suspend_again(state));</span><br><span class="line"></span><br><span class="line"> Resume_devices:</span><br><span class="line"> suspend_test_start();</span><br><span class="line"> dpm_resume_end(PMSG_RESUME);</span><br><span class="line"> suspend_test_finish(&quot;resume devices&quot;);</span><br><span class="line"> trace_suspend_resume(TPS(&quot;resume_console&quot;), state, true);</span><br><span class="line"> resume_console();</span><br><span class="line"> trace_suspend_resume(TPS(&quot;resume_console&quot;), state, false);</span><br><span class="line"></span><br><span class="line"> Close:</span><br><span class="line"> platform_resume_end(state);</span><br><span class="line"> return error;</span><br><span class="line"></span><br><span class="line"> Recover_platform:</span><br><span class="line"> platform_recover(state);</span><br><span class="line"> goto Resume_devices;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>suspend_devices_and_enter中会挂起console,并执行设备驱动的-&gt;prepare和-&gt;suspend回调函数,然后在suspend_enter中进入休眠状态,通过返回值告知是否enter成功,同时通过wakeup指针,告知调用者,是否有wakeup事件发生,导致进入休眠失败。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/kernel/power/suspend.c</span><br><span class="line"></span><br><span class="line">static int suspend_enter(suspend_state_t state, bool *wakeup)</span><br><span class="line">&#123;</span><br><span class="line"> char suspend_abort[MAX_SUSPEND_ABORT_LEN];</span><br><span class="line"> int error, last_dev;</span><br><span class="line"> // 调用suspend_ops-&gt;prepare()</span><br><span class="line"> error = platform_suspend_prepare(state);</span><br><span class="line"> if (error)</span><br><span class="line"> goto Platform_finish;</span><br><span class="line"> // 调用所有设备的-&gt;suspend_late和-&gt;suspend_noirq回调函数</span><br><span class="line"> error = dpm_suspend_late(PMSG_SUSPEND);</span><br><span class="line"> if (error) &#123;</span><br><span class="line"> last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;</span><br><span class="line"> last_dev %= REC_FAILED_NUM;</span><br><span class="line"> printk(KERN_ERR &quot;PM: late suspend of devices failed\n&quot;);</span><br><span class="line"> log_suspend_abort_reason(&quot;%s device failed to power down&quot;,</span><br><span class="line"> suspend_stats.failed_devs[last_dev]);</span><br><span class="line"> goto Platform_finish;</span><br><span class="line"> &#125;</span><br><span class="line"> // 调用suspend_ops的prepare_late回调</span><br><span class="line"> error = platform_suspend_prepare_late(state);</span><br><span class="line"> if (error)</span><br><span class="line"> goto Devices_early_resume;</span><br><span class="line"></span><br><span class="line"> error = dpm_suspend_noirq(PMSG_SUSPEND);</span><br><span class="line"> if (error) &#123;</span><br><span class="line"> last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;</span><br><span class="line"> last_dev %= REC_FAILED_NUM;</span><br><span class="line"> printk(KERN_ERR &quot;PM: noirq suspend of devices failed\n&quot;);</span><br><span class="line"> log_suspend_abort_reason(&quot;noirq suspend of %s device failed&quot;,</span><br><span class="line"> suspend_stats.failed_devs[last_dev]);</span><br><span class="line"> goto Platform_early_resume;</span><br><span class="line"> &#125;</span><br><span class="line"> error = platform_suspend_prepare_noirq(state);</span><br><span class="line"> if (error)</span><br><span class="line"> goto Platform_wake;</span><br><span class="line"></span><br><span class="line"> if (suspend_test(TEST_PLATFORM))</span><br><span class="line"> goto Platform_wake;</span><br><span class="line"></span><br><span class="line"> /*</span><br><span class="line"> * 如果是suspend to freeze,执行相应的操作,包括冻结进程</span><br><span class="line"> * suspended devices(参数为PM_SUSPEND_FREEZE)、cpu进入idle。</span><br><span class="line"> * 如果有任何事件使CPU从idle状态退出,跳至Platform_wake处,执行wake操作。</span><br><span class="line"> */</span><br><span class="line"> if (state == PM_SUSPEND_FREEZE) &#123;</span><br><span class="line"> trace_suspend_resume(TPS(&quot;machine_suspend&quot;), state, true);</span><br><span class="line"> freeze_enter();</span><br><span class="line"> trace_suspend_resume(TPS(&quot;machine_suspend&quot;), state, false);</span><br><span class="line"> goto Platform_wake;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> // 禁止所有的非boot cpu</span><br><span class="line"> error = disable_nonboot_cpus();</span><br><span class="line"> if (error || suspend_test(TEST_CPUS)) &#123;</span><br><span class="line"> log_suspend_abort_reason(&quot;Disabling non-boot cpus failed&quot;);</span><br><span class="line"> goto Enable_cpus;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> //关全局中断</span><br><span class="line"> arch_suspend_disable_irqs();</span><br><span class="line"> BUG_ON(!irqs_disabled());</span><br><span class="line"></span><br><span class="line"> // 调用syscore_suspend,suspend system core</span><br><span class="line"> error = syscore_suspend();</span><br><span class="line"> if (!error) &#123;</span><br><span class="line"> // 检查一下suspend执行这段时间内,是否有唤醒事件发生</span><br><span class="line"> *wakeup = pm_wakeup_pending();</span><br><span class="line"> if (!(suspend_test(TEST_CORE) || *wakeup)) &#123;</span><br><span class="line"> trace_suspend_resume(TPS(&quot;machine_suspend&quot;),</span><br><span class="line"> state, true);</span><br><span class="line"> // 调用suspend_ops-&gt;enter进入休眠状态 </span><br><span class="line"> error = suspend_ops-&gt;enter(state);</span><br><span class="line"> trace_suspend_resume(TPS(&quot;machine_suspend&quot;),</span><br><span class="line"> state, false);</span><br><span class="line"> events_check_enabled = false;</span><br><span class="line"> &#125; else if (*wakeup) &#123;</span><br><span class="line"> pm_get_active_wakeup_sources(suspend_abort,</span><br><span class="line"> MAX_SUSPEND_ABORT_LEN);</span><br><span class="line"> log_suspend_abort_reason(suspend_abort);</span><br><span class="line"> error = -EBUSY;</span><br><span class="line"> &#125;</span><br><span class="line"> syscore_resume();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> arch_suspend_enable_irqs();</span><br><span class="line"> BUG_ON(irqs_disabled());</span><br><span class="line"></span><br><span class="line"> Enable_cpus:</span><br><span class="line"> enable_nonboot_cpus();</span><br><span class="line"></span><br><span class="line"> Platform_wake:</span><br><span class="line"> platform_resume_noirq(state);</span><br><span class="line"> dpm_resume_noirq(PMSG_RESUME);</span><br><span class="line">suspend_ops-&gt;enter</span><br><span class="line"> Platform_early_resume:</span><br><span class="line"> platform_resume_early(state);</span><br><span class="line"></span><br><span class="line"> Devices_early_resume:</span><br><span class="line"> dpm_resume_early(PMSG_RESUME);</span><br><span class="line"></span><br><span class="line"> Platform_finish:</span><br><span class="line"> platform_resume_finish(state);</span><br><span class="line"> return error;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>suspend_enter中经过一系列的处理,最终在suspend_ops-&gt;enter中进入休眠状态,当唤醒事件发生,系统唤醒,该函数接着执行resume动作,并最终返回,resume动作基本上是suspend的反动作。</p>
</content>
<summary type="html">
<blockquote>
<p>kernel/msm-4.4/kernel/power/main.c<br>kernel/msm-4.4/kernel/power/suspend.c<br>kernel/msm-4.4/kernel/power/process.c<br>kern
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="PowerManagement" scheme="http://robinheztto.com/tags/PowerManagement/"/>
</entry>
<entry>
<title>Android电源管理系列之System wakeup events framework</title>
<link href="http://robinheztto.com/2017/05/01/android-power-system-wakeup-events-framework/"/>
<id>http://robinheztto.com/2017/05/01/android-power-system-wakeup-events-framework/</id>
<published>2017-05-01T07:46:56.000Z</published>
<updated>2018-06-24T16:24:25.000Z</updated>
<content type="html"><blockquote>
<p>kernel/msm-4.4/drivers/base/power/wakeup.c<br>kernel/msm-4.4/include/linux/pm_wakeup.h<br>kernel/msm-4.4/include/linux/pm.h<br>kernel/msm-4.4/include/linux/device.h</p>
</blockquote>
<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>Android以Linux kernel为系统内核,其电源管理也是基于Linux电源管理子系统的,但是由于传统的Linux系统主要针对PC而非移动设备,对于PC系统,Linux默认是在用户不再使用时才再触发系统进入休眠(STR、Standby、Hibernate),但是对于移动设备的使用特点而言,并没有明确的不再使用设备的时候,用户随时随地都可能需要使用设备,于是在Android上就有提出了“Opportunistic suspend”的概念,即逮到机会就睡直到下次被唤醒,以适应移动设备的使用特点。</p>
<p>早期,Android为解决该问题,在标准Linux的基础上增加了Early Suspend和Late Resume机制,Early suspend是在熄屏后,提前将一些不会用到的设备(比如背光、重力感应器和触摸屏等设备)关闭,但此时系统仍能持有wake lock后台运行。该方案将Linux原来suspend的流程改变,并增加了Android自己的处理函数,与kernel的流程与机制相冲突,另外一个问题就是存在suspend和wakeup events之间的同步问题,比如当系统进入suspend流程中,会进行freeze process,device prepared,device suspend,disabled irq等操作,如果在suspend流程中有wakeup events产生,而此时系统无法从suspend过程中唤醒。</p>
<p>后来Linux加入wakeup events framework,包括wake lock、wakeup count、autosleep等机制。用来解决system suspend和system wakeup events之间的同步问题。同时在Android4.4中,Android中也去掉了之前的”wakelocks”机制,利用wakeup events framework重新设计了wakelocks,并且维持上层API不变。</p>
<p>system suspend和system wakeup events之间的同步问题:</p>
<ul>
<li>内核空间的同步:<br>wakeup events产生后,通常是以中断的形式通知device driver。driver会处理events,处理的过程中,系统不能suspend。</li>
<li>用户空间的同步:<br>一般情况下,driver对wakeup events处理后,会交给用户空间程序继续处理,处理的过程,也不允许suspend。这又可以分为两种情况:<ol>
<li>进行后续处理的用户进程,根本没有机会被调度,即该wakeup events无法上报到用户空间。</li>
<li>进行后续处理的用户进程被调度,处理的过程中(以及处理结束后,决定终止suspend操作),系统不能suspend。(wake lock功能)</li>
</ol>
</li>
</ul>
<p>wakeup events framework主要解决上述三个同步问题,内核空间的同步(framework的核心功能),用户空间的同步情形1(wakeup count功能),用户空间的同步情形2(wake lock功能)。 </p>
<h1 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h1><p>下面是wakeup events framework的architecture图(来自<a href="http://www.wowotech.net" target="_blank" rel="external">蜗窝科技</a>)</p>
<div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/wakeup-events-framework-arch.jpeg?raw=true" alt="wakeup events framework architecture"><br></div><br>wakeup events framework sysfs将设备的wakeup信息,以sysfs的形式提供到用户空间,供用户空间访问(在drivers/base/power/sysfs.c中实现)。<br><br>## wakeup source<br>在kernel中,只有设备才能唤醒系统,但并不是所有设备都具备唤醒系统的能力,具备唤醒能力的设备即“wakeup source”,会在设备结构体struce device中标志该设备具有唤醒能力。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&gt; kernel/msm-4.4/include/linux/device.h</span><br><span class="line"></span><br><span class="line">struct device &#123; </span><br><span class="line"> ... </span><br><span class="line"> struct dev_pm_info power; </span><br><span class="line"> struct dev_pm_domain *pm_domain; </span><br><span class="line"> ... </span><br><span class="line">&#125; </span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt; kernel/msm-4.4/include/linux/pm_wakeup.h</span><br><span class="line"></span><br><span class="line">static inline bool device_can_wakeup(struct device *dev)</span><br><span class="line">&#123;</span><br><span class="line"> return dev-&gt;power.can_wakeup;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static inline bool device_may_wakeup(struct device *dev)</span><br><span class="line">&#123;</span><br><span class="line"> return dev-&gt;power.can_wakeup &amp;&amp; !!dev-&gt;power.wakeup;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br>由device_can_wakeup()函数可知,通过dev-&gt;power.can_wakeup来判断该设备是否能唤醒系统,struct dev_pm_info的定义如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/include/linux/pm.h</span><br><span class="line"></span><br><span class="line">struct dev_pm_info &#123;</span><br><span class="line"> ......</span><br><span class="line"> unsigned int can_wakeup:1;</span><br><span class="line"> ......</span><br><span class="line">#ifdef CONFIG_PM_SLEEP</span><br><span class="line"> ......</span><br><span class="line"> struct wakeup_source *wakeup;</span><br><span class="line"> ......</span><br><span class="line">#else</span><br><span class="line"> unsigned int should_wakeup:1;</span><br><span class="line">#endif</span><br><span class="line"> ......</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><br><br>struct dev_pm_info中的can_wakeup标识该设备是否具有唤醒能力。具备唤醒能力的设备在sys/devices/xxx/下存在power相关目录,用于提供所有的wakeup信息,这些信息是以struct wakeup_source的结构组织,即struct dev_pm_info中的wakeup指针。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/include/linux/pm_wakeup.h</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * struct wakeup_source - Representation of wakeup sources</span><br><span class="line"> *</span><br><span class="line"> * @name: 唤醒源的名字</span><br><span class="line"> * @entry: 用来将唤醒源挂到链表上,用于管理</span><br><span class="line"> * @lock: 同步机制,用于访问链表时使用</span><br><span class="line"> * @wakeirq:Optional device specific wakeirq</span><br><span class="line"> * @timer: 定时器,用于设置该唤醒源的超时时间</span><br><span class="line"> * @timer_expires: 定时器的超时时间</span><br><span class="line"> * @total_time: wakeup source处于active状态的总时间,可指示该wakeup source对应的设备的繁忙程度、耗电等级</span><br><span class="line"> * @max_time: wakeup source处于active状态的最长时间(越长越不合理)</span><br><span class="line"> * @last_time: wakeup source处于active状态的上次时间</span><br><span class="line"> * @prevent_sleep_time: wakeup source阻止系统自动休眠的总时间</span><br><span class="line"> * @event_count: wakeup source上报wakeup event的个数</span><br><span class="line"> * @active_count: wakeup source处于active状态的次数</span><br><span class="line"> * @relax_count: wakeup source处于deactive状态的次数</span><br><span class="line"> * @expire_count: wakeup source timeout次数</span><br><span class="line"> * @wakeup_count: wakeup source abort睡眠的次数</span><br><span class="line"> * @active: wakeup source的状态</span><br><span class="line"> * @has_timeout: The wakeup source has been activated with a timeout.</span><br><span class="line"> */</span><br><span class="line">struct wakeup_source &#123;</span><br><span class="line"> const char *name;</span><br><span class="line"> struct list_head entry;</span><br><span class="line"> spinlock_t lock;</span><br><span class="line"> struct wake_irq *wakeirq;</span><br><span class="line"> struct timer_list timer;</span><br><span class="line"> unsigned long timer_expires;</span><br><span class="line"> ktime_t total_time;</span><br><span class="line"> ktime_t max_time;</span><br><span class="line"> ktime_t last_time;</span><br><span class="line"> ktime_t start_prevent_time;</span><br><span class="line"> ktime_t prevent_sleep_time;</span><br><span class="line"> unsigned long event_count;</span><br><span class="line"> unsigned long active_count;</span><br><span class="line"> unsigned long relax_count;</span><br><span class="line"> unsigned long expire_count;</span><br><span class="line"> unsigned long wakeup_count;</span><br><span class="line"> bool active:1;</span><br><span class="line"> bool autosleep_enabled:1;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><br><br>wakeup source代表一个具有唤醒能力的设备,该设备产生的可以唤醒系统的事件,就称作wakeup event。当wakeup source产生wakeup event时,需要将wakeup source切换为activate状态;当wakeup event处理完毕后,要切换为deactivate状态。当wakeup source产生wakeup event时,需要切换到activate状态,但并不是每次都需要切换,因此有可能已经处于activate状态了。因此active_count可能小于event_count,换句话说,很有可能在前一个wakeup event没被处理完时,又产生了一个,这从一定程度上反映了wakeup source所代表的设备的繁忙程度。wakeup source在suspend过程中产生wakeup event的话,就会终止suspend过程,wakeup_count记录了wakeup source终止suspend过程的次数(如果发现系统总是suspend失败,检查一下各个wakeup source的该变量,就可以知道问题出在谁身上了)。<br>为了方便查看系统的wakeup sources的信息,linux系统在/sys/kernel/debug下创建了一个”wakeup_sources”文件,此文件记录了系统的唤醒源的详细信息。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/drivers/base/power/wakeup.c</span><br><span class="line"></span><br><span class="line">static int wakeup_sources_stats_show(struct seq_file *m, void *unused)</span><br><span class="line">&#123;</span><br><span class="line"> struct wakeup_source *ws;</span><br><span class="line"></span><br><span class="line"> seq_puts(m, &quot;name\t\tactive_count\tevent_count\twakeup_count\t&quot;</span><br><span class="line"> &quot;expire_count\tactive_since\ttotal_time\tmax_time\t&quot;</span><br><span class="line"> &quot;last_change\tprevent_suspend_time\n&quot;);</span><br><span class="line"></span><br><span class="line"> rcu_read_lock();</span><br><span class="line"> list_for_each_entry_rcu(ws, &amp;wakeup_sources, entry)</span><br><span class="line"> print_wakeup_source_stats(m, ws);</span><br><span class="line"> rcu_read_unlock();</span><br><span class="line"></span><br><span class="line"> print_wakeup_source_stats(m, &amp;deleted_ws);</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static int wakeup_sources_stats_open(struct inode *inode, struct file *file)</span><br><span class="line">&#123;</span><br><span class="line"> return single_open(file, wakeup_sources_stats_show, NULL);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static const struct file_operations wakeup_sources_stats_fops = &#123;</span><br><span class="line"> .owner = THIS_MODULE,</span><br><span class="line"> .open = wakeup_sources_stats_open,</span><br><span class="line"> .read = seq_read,</span><br><span class="line"> .llseek = seq_lseek,</span><br><span class="line"> .release = single_release,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">static int __init wakeup_sources_debugfs_init(void)</span><br><span class="line">&#123;</span><br><span class="line"> wakeup_sources_stats_dentry = debugfs_create_file(&quot;wakeup_sources&quot;,</span><br><span class="line"> S_IRUGO, NULL, NULL, &amp;wakeup_sources_stats_fops);</span><br><span class="line"> return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">postcore_initcall(wakeup_sources_debugfs_init);</span><br></pre></td></tr></table></figure><br><br>如下图示,通过<code>cat /sys/kernel/debug/wakeup_sources</code>获取wakeup_sources信息:<br><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/sys_kernel_debug_wakeup_sources.png?raw=true" alt="sys_kernel_debug_wakeup_sources"><br></div>
<h2 id="机制"><a href="#机制" class="headerlink" title="机制"></a>机制</h2><p>wakeup events framework中抽象了wakeup source和wakeup event的概念,向各个device driver提供wakeup source的注册、使能等及wakeup event的上报、停止等接口,同时也向上层提供wakeup event的查询接口,以判断是否可以suspend或者是否需要终止正在进行的suspend。</p>
<h3 id="pm-stay-awake"><a href="#pm-stay-awake" class="headerlink" title="pm_stay_awake()"></a>pm_stay_awake()</h3><p>当设备有wakeup event正在处理时,需要调用该接口通知PM core,该接口的实现如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/drivers/base/power/wakeup.c</span><br><span class="line"></span><br><span class="line">void pm_stay_awake(struct device *dev)</span><br><span class="line">&#123;</span><br><span class="line"> unsigned long flags;</span><br><span class="line"></span><br><span class="line"> if (!dev)</span><br><span class="line"> return;</span><br><span class="line"></span><br><span class="line"> spin_lock_irqsave(&amp;dev-&gt;power.lock, flags);</span><br><span class="line"> __pm_stay_awake(dev-&gt;power.wakeup);</span><br><span class="line"> spin_unlock_irqrestore(&amp;dev-&gt;power.lock, flags);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void __pm_stay_awake(struct wakeup_source *ws)</span><br><span class="line">&#123;</span><br><span class="line"> unsigned long flags;</span><br><span class="line"></span><br><span class="line"> if (!ws)</span><br><span class="line"> return;</span><br><span class="line"></span><br><span class="line"> spin_lock_irqsave(&amp;ws-&gt;lock, flags);</span><br><span class="line"></span><br><span class="line"> wakeup_source_report_event(ws);</span><br><span class="line"> del_timer(&amp;ws-&gt;timer);</span><br><span class="line"> ws-&gt;timer_expires = 0;</span><br><span class="line"></span><br><span class="line"> spin_unlock_irqrestore(&amp;ws-&gt;lock, flags);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static void wakeup_source_report_event(struct wakeup_source *ws)</span><br><span class="line">&#123;</span><br><span class="line"> ws-&gt;event_count++;</span><br><span class="line"> /* This is racy, but the counter is approximate anyway. */</span><br><span class="line"> if (events_check_enabled)</span><br><span class="line"> ws-&gt;wakeup_count++;</span><br><span class="line"></span><br><span class="line"> if (!ws-&gt;active)</span><br><span class="line"> wakeup_source_activate(ws);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>pm_stay_awake中直接调用<strong>pm_stay_awake,\</strong>pm_stay_awake直接调用wakeup_source_report_event。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/drivers/base/power/wakeup.c</span><br><span class="line"></span><br><span class="line">static void wakeup_source_report_event(struct wakeup_source *ws)</span><br><span class="line">&#123;</span><br><span class="line"> ws-&gt;event_count++;</span><br><span class="line"> /* This is racy, but the counter is approximate anyway. */</span><br><span class="line"> if (events_check_enabled)</span><br><span class="line"> ws-&gt;wakeup_count++;</span><br><span class="line"></span><br><span class="line"> if (!ws-&gt;active)</span><br><span class="line"> wakeup_source_activate(ws);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>wakeup_source_report_event中增加wakeup source的event_count次数,即表示该source又产生了一个event。然后根据events_check_enabled变量的状态,增加wakeup_count。如果wakeup source没有active,则调用wakeup_source_activate进行activate操作。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/drivers/base/power/wakeup.c</span><br><span class="line"></span><br><span class="line">static void wakeup_source_activate(struct wakeup_source *ws)</span><br><span class="line">&#123;</span><br><span class="line"> unsigned int cec;</span><br><span class="line"></span><br><span class="line"> /*</span><br><span class="line"> * active wakeup source should bring the system</span><br><span class="line"> * out of PM_SUSPEND_FREEZE state</span><br><span class="line"> */</span><br><span class="line"> freeze_wake();</span><br><span class="line"></span><br><span class="line"> ws-&gt;active = true;</span><br><span class="line"> ws-&gt;active_count++;</span><br><span class="line"> ws-&gt;last_time = ktime_get();</span><br><span class="line"> if (ws-&gt;autosleep_enabled)</span><br><span class="line"> ws-&gt;start_prevent_time = ws-&gt;last_time;</span><br><span class="line"></span><br><span class="line"> /* Increment the counter of events in progress. */</span><br><span class="line"> cec = atomic_inc_return(&amp;combined_event_count);</span><br><span class="line"></span><br><span class="line"> trace_wakeup_source_activate(ws-&gt;name, cec);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>wakeup_source_activate中首先调用freeze_wake,将系统从suspend to freeze状态下唤醒,然后设置active标志,增加active_count,更新last_time。如果使能了autosleep,更新start_prevent_time,此刻该wakeup source会开始阻止系统auto sleep。增加“wakeup events in progress”计数,增加该计数意味着系统正在处理的wakeup event数目不为零,即系统不能suspend。</p>
<h2 id="pm-relax"><a href="#pm-relax" class="headerlink" title="pm_relax()"></a>pm_relax()</h2><p>pm_relax和pm_stay_awake成对出现,用于在wakeup event处理结束后通知PM core,其实现如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/drivers/base/power/wakeup.c</span><br><span class="line"></span><br><span class="line">void pm_relax(struct device *dev)</span><br><span class="line">&#123;</span><br><span class="line"> unsigned long flags;</span><br><span class="line"></span><br><span class="line"> if (!dev)</span><br><span class="line"> return;</span><br><span class="line"></span><br><span class="line"> spin_lock_irqsave(&amp;dev-&gt;power.lock, flags);</span><br><span class="line"> __pm_relax(dev-&gt;power.wakeup);</span><br><span class="line"> spin_unlock_irqrestore(&amp;dev-&gt;power.lock, flags);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void __pm_relax(struct wakeup_source *ws)</span><br><span class="line">&#123;</span><br><span class="line"> unsigned long flags;</span><br><span class="line"></span><br><span class="line"> if (!ws)</span><br><span class="line"> return;</span><br><span class="line"></span><br><span class="line"> spin_lock_irqsave(&amp;ws-&gt;lock, flags);</span><br><span class="line"> if (ws-&gt;active)</span><br><span class="line"> wakeup_source_deactivate(ws);</span><br><span class="line"> spin_unlock_irqrestore(&amp;ws-&gt;lock, flags);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>pm_relax中直接调用<strong>pm_relax,\</strong>pm_relax判断wakeup source如果处于active状态,则调用wakeup_source_deactivate接口,deactivate该wakeup source。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; kernel/msm-4.4/drivers/base/power/wakeup.c</span><br><span class="line"></span><br><span class="line">static void wakeup_source_deactivate(struct wakeup_source *ws)</span><br><span class="line">&#123;</span><br><span class="line"> unsigned int cnt, inpr, cec;</span><br><span class="line"> ktime_t duration;</span><br><span class="line"> ktime_t now;</span><br><span class="line"></span><br><span class="line"> ws-&gt;relax_count++;</span><br><span class="line"> if (ws-&gt;relax_count != ws-&gt;active_count) &#123;</span><br><span class="line"> ws-&gt;relax_count--;</span><br><span class="line"> return;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> ws-&gt;active = false;</span><br><span class="line"></span><br><span class="line"> now = ktime_get();</span><br><span class="line"> duration = ktime_sub(now, ws-&gt;last_time);</span><br><span class="line"> ws-&gt;total_time = ktime_add(ws-&gt;total_time, duration);</span><br><span class="line"> if (ktime_to_ns(duration) &gt; ktime_to_ns(ws-&gt;max_time))</span><br><span class="line"> ws-&gt;max_time = duration;</span><br><span class="line"></span><br><span class="line"> ws-&gt;last_time = now;</span><br><span class="line"> del_timer(&amp;ws-&gt;timer);</span><br><span class="line"> ws-&gt;timer_expires = 0;</span><br><span class="line"></span><br><span class="line"> if (ws-&gt;autosleep_enabled)</span><br><span class="line"> update_prevent_sleep_time(ws, now);</span><br><span class="line"></span><br><span class="line"> /*</span><br><span class="line"> * Increment the counter of registered wakeup events and decrement the</span><br><span class="line"> * couter of wakeup events in progress simultaneously.</span><br><span class="line"> */</span><br><span class="line"> cec = atomic_add_return(MAX_IN_PROGRESS, &amp;combined_event_count);</span><br><span class="line"> trace_wakeup_source_deactivate(ws-&gt;name, cec);</span><br><span class="line"></span><br><span class="line"> split_counters(&amp;cnt, &amp;inpr);</span><br><span class="line"> if (!inpr &amp;&amp; waitqueue_active(&amp;wakeup_count_wait_queue))</span><br><span class="line"> wake_up(&amp;wakeup_count_wait_queue);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><ol>
<li><a href="http://www.wowotech.net/pm_subsystem/wakeup_events_framework.html" target="_blank" rel="external">蜗窝科技:Wakeup events framework</a></li>
<li><a href="http://blog.csdn.net/wlwl0071986/article/details/42672591" target="_blank" rel="external">CSDN:三种休眠机制的分析和比较</a></li>
</ol>
</content>
<summary type="html">
<blockquote>
<p>kernel/msm-4.4/drivers/base/power/wakeup.c<br>kernel/msm-4.4/include/linux/pm_wakeup.h<br>kernel/msm-4.4/include/linux/pm.h<
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="PowerManagement" scheme="http://robinheztto.com/tags/PowerManagement/"/>
</entry>
<entry>
<title>Android电源管理系列之Basic</title>
<link href="http://robinheztto.com/2017/04/20/android-power-basic/"/>
<id>http://robinheztto.com/2017/04/20/android-power-basic/</id>
<published>2017-04-20T01:07:54.000Z</published>
<updated>2018-01-07T04:07:05.000Z</updated>
<content type="html"><p><strong>1. Sleep/Suspend</strong><br>系统休眠Sleep,Linux Kernel中称作Suspend。系统进入Suspend状态确切来说时CPU进入了Suspend模式,因为对整个系统来说CPU休眠是整个系统休眠的先决条件。CPU Suspend即CPU进入Wait for interrupt状态(WFI),SW完全不跑了,停在suspend workqueue里面。<br>Android系统从灭屏到系统进入Suspend的大体流程框架如下:</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/suspend_flow.png?raw=true" alt="Suspend flow"><br></div><br>相关代码如下:</p>
<blockquote>
<p>/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java<br>/frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp<br>/system/core/libsuspend/<br>/kernel-x.x/kernel/power/</p>
</blockquote>
<p><strong>2. SPM</strong><br>SPM即System Power Manager,管理着包括AP,Modem,Connectivity等子系统。在CPU进入WFI状态后,整个系统就依靠SPM监控各个子系统的状态来控制睡眠/唤醒的流程。<br>SPM控制Cpu Suspend之后系统是否能掉到最小电流,当系统的关键资源(memory、clock)没有任何使用的时候,它就会让系统进入一个真正的深睡状态(最小电流),但只要检测到有任何资源请求还没释放,系统就无法降到底电流。在底电流的debug流程中,不仅仅要看CPU有没有Suspend成功,还要看SPM的状态是否正确。</p>
<p>MTK平台:<br>CPU在进入WFI状态前会把SPM的firmware写入到SPM里的可编程控制器PCM中(Programmable Command Master),然后PCM就依据firmware的逻辑来控制SPM的工作。系统中存在32k,26M二个时钟,系统工作在最小电流的时候,SPM只依靠32K时钟工作,因此要判断系统是不是已经到深休状态,就要看26M有没有关闭。</p>
<p><div align="center"><br><img src="https://github.com/RobinHeZtto/Resource/blob/master/blog/image/android/power/26M_control.png?raw=true" alt="26M clock control"><br></div><br>如上图所示,26M时钟有没有关,只需要看SCLKENA信号有没有关闭,而SPM对这个信号的输出以及子系统的信号输入,都记录在SPM的寄存器里面,这个就是我们通过log排查的依据。<br>相关代码如下:</p>
<blockquote>
<p>/kernel-x.x/drivers/misc/mediatek/base/power/spm_vx/</p>
</blockquote>
</content>
<summary type="html">
<p><strong>1. Sleep/Suspend</strong><br>系统休眠Sleep,Linux Kernel中称作Suspend。系统进入Suspend状态确切来说时CPU进入了Suspend模式,因为对整个系统来说CPU休眠是整个系统休眠的先决条件。CPU Su
</summary>
<category term="Android" scheme="http://robinheztto.com/tags/Android/"/>
<category term="Power" scheme="http://robinheztto.com/tags/Power/"/>
</entry>