-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
2247 lines (2175 loc) · 116 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">
<id>https://jxiaow.gitee.io</id>
<title>Xiaowu</title>
<updated>2021-07-07T02:13:30.235Z</updated>
<generator>https://github.com/jpmonette/feed</generator>
<link rel="alternate" href="https://jxiaow.gitee.io"/>
<link rel="self" href="https://jxiaow.gitee.io/atom.xml"/>
<subtitle>心若没有栖息的地方,到哪里都是在流浪</subtitle>
<logo>https://jxiaow.gitee.io/images/avatar.png</logo>
<icon>https://jxiaow.gitee.io/favicon.ico</icon>
<rights>All rights reserved 2021, Xiaowu</rights>
<entry>
<title type="html"><![CDATA[Git 基本使用]]></title>
<id>https://jxiaow.gitee.io/posts/b8d683be/</id>
<link href="https://jxiaow.gitee.io/posts/b8d683be/">
</link>
<updated>2021-03-17T08:26:14.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>以下内容是在初使用Git的时的笔记记录,会不定时更新。</p>
</blockquote>
<h1 id="1-git使用操作">1. Git使用操作</h1>
<h2 id="11-代理">1.1. 代理</h2>
<ul>
<li>设置代理</li>
</ul>
<p>如果需要下载墙外的仓库:</p>
<pre><code class="language-bash">//1080 可以根据自己买的vpn服务器端口
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'
</code></pre>
<ul>
<li>删除代理</li>
</ul>
<pre><code>git config --global --unset http.proxy
git config --global --unset https.proxy
</code></pre>
<h2 id="12-android创建忽略文件gitignore">1.2. Android创建忽略文件<code>.gitignore</code></h2>
<ul>
<li>一般如果使用Android Studio创建的时候,IDE会自动给我创建<code>.gitignore</code>文件,但有时候我们也需要自定义此文件。因此,我们可以从 <a href="https://github.com/github/gitignore">github/gitignore</a> 项目中下载相应的文件,放到我们项目的根目录即可。</li>
</ul>
<h2 id="13-git撤销commit">1.3. git撤销commit</h2>
<pre><code>git commit --amend
</code></pre>
<h2 id="14-git-回到某个版本">1.4. git 回到某个版本</h2>
<pre><code>git reset id //只更改版本,不修改代码
git reset --hard id //版本和代码都修改
</code></pre>
<h2 id="15-git-多url推送">1.5. git 多url推送</h2>
<p>第一个url</p>
<pre><code>git remote add origin url
</code></pre>
<p>然后其他的</p>
<pre><code>git remote set-url --add origin url
</code></pre>
<h2 id="16-git-push-origin-master">1.6. git push origin master</h2>
<ul>
<li>git push 推送到默认分支</li>
<li>git push origin 推送到主机为origin的远程服务器上</li>
<li>git push origin master 推送到主机为origin的服务器上的master分支</li>
</ul>
<h2 id="17-git-放弃本地修改强制拉取更新">1.7. git 放弃本地修改,强制拉取更新</h2>
<ol>
<li>从服务器拉取数据到本地</li>
</ol>
<pre><code class="language-shell">git fetch --all
或者
git fetch 主机名 分支 (example: git fetch origin dev)
</code></pre>
<ol start="2">
<li>把Head指向最新拉取的分支</li>
</ol>
<pre><code class="language-SHELL">git reset --hard 主机名/分支 (example: git reset --hard origin/dev)
</code></pre>
<ol start="3">
<li>重新拉取(这步可忽略)</li>
</ol>
<pre><code class="language-shell">git pull 主机名 分支
</code></pre>
<h2 id="18-git-修改分支名称">1.8. git 修改分支名称</h2>
<pre><code class="language-shell">git branch -m oldBranchName newBranchName //修改本地的
git push //推送到远程分支
</code></pre>
<h2 id="19-git-push-出现错误error-failed-to-push-some-refs">1.9. git push 出现错误:<code>error: failed to push some refs</code></h2>
<p>1、在使用git 对源代码进行push到git仓库时可能会出错</p>
<p>2、出现错误的主要原因是本地和远程仓库中的代码不一致导致</p>
<p>3、可以通过如下命令进行代码合并【注:pull=fetch+merge]</p>
<pre><code class="language-shell">git pull --rebase origin master
</code></pre>
<p>4、此时再执行语句 git push 即可完成代码上传到远程仓库</p>
<h1 id="2-查看所有分支情况">2. 查看所有分支情况</h1>
<pre><code class="language-bash">git branch -a
</code></pre>
<h2 id="21-删除远程分支">2.1. 删除远程分支</h2>
<pre><code class="language-shell">git push origin --delete dev
</code></pre>
<h2 id="22-git提示auto-packing-the-repository-in-background-for-optimum-performance">2.2. git提示Auto packing the repository in background for optimum performance</h2>
<p>查资料,原来是自己本地一些 “悬空对象”太多(git删除分支或者清空stash的时候,这些其实还没有真正删除,成为悬空对象,我们可以使用merge命令可以从中恢复一些文件)</p>
<p>解决: (删除掉.)<br>
1.输入命令:git fsck -.-lost-found,可以看到好多“dangling commit”<br>
2.清空他们:git gc -.-prune=now,完成</p>
<h3 id="git-rebase-i-head~xxx是修改git-历史记录的一个很有用的命令">"git rebase -i HEAD~xxx"是修改git 历史记录的一个很有用的命令。</h3>
<p>但是有时在执行该命令时会出现以下错误:<br>
$ git rebase –i HEAD~8<br>
fatal: Needed a single revision<br>
invalid upstream –i</p>
<p>二、错误原因<br>
当前执行操作的点不在任何分支上,或者可能rebase后面的参数是一个错误的分支;<br>
当前执行操作的点前面的提交不够8个。</p>
<p>三、解决办法<br>
确认'-i' 之后的参数是否正确;<br>
确认需要rebase的提交相对于'HEAD'的序号,一种极端情况是想从当前分支的第一个提交开始rebase,可以使用以下命令:git rebase -i --root。</p>
<h2 id="3-修改本地分支名称和远程分支名称">3 修改本地分支名称和远程分支名称</h2>
<h3 id="本地分支重名名">本地分支重名名</h3>
<pre><code class="language-shell">git branch -m old_branch new_branch
</code></pre>
<h3 id="删除远程分支并重新推送">删除远程分支并重新推送</h3>
<pre><code class="language-shell">git push origin :old_branch
git push origin new_branch:new_branch
</code></pre>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Binder解析]]></title>
<id>https://jxiaow.gitee.io/posts/7425384b/</id>
<link href="https://jxiaow.gitee.io/posts/7425384b/">
</link>
<updated>2021-01-31T13:32:11.000Z</updated>
<content type="html"><![CDATA[<figure data-type="image" tabindex="1"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/cbe191fcba5fc5e06c7cd120d4f6a437-Binder-0748cb.png" alt="Binder" loading="lazy"></figure>
<ol>
<li>
<p>Binder 是什么?</p>
<blockquote>
<p>ipc通信方式</p>
</blockquote>
</li>
<li>
<p>什么时候需要用到进程间通信?</p>
<blockquote>
<p>webview访问,图片加载,推送 ,比较耗内存,单开一个会比较有保障, 系统的一些服务,如通话,闹钟,输入法服务等等</p>
</blockquote>
</li>
<li>
<p>为什么要多进程?</p>
<blockquote>
<p>虚拟机分配给各个应用的每个进程内存都是有限制的,耗内存的服务,如果不开一个服务,app的主进程内存会很快耗尽,会出现OOM</p>
</blockquote>
</li>
<li>
<p>进程间通信为什么需要用到Binder?</p>
<p>本篇主题。</p>
</li>
</ol>
<h3 id="linux进程空间划分">Linux进程空间划分</h3>
<ul>
<li>
<p>一个进程空间分为 <strong>用户空间</strong> & <strong>内核空间(Kernel)</strong>,即把进程内 用户 & 内核 隔离开来</p>
</li>
<li>
<p>二者区别:</p>
<ul>
<li>进程间,用户空间的数据不可共享,所以用户空间 = 不可共享空间</li>
<li>进程间,内核空间的数据可共享,所以内核空间 = 可共享空间</li>
</ul>
<blockquote>
<p>所有进程共用1个内核空间</p>
</blockquote>
</li>
<li>
<p>进程内 用户空间 & 内核空间 进行交互 需通过 <strong>系统调用</strong>,主要通过函数:</p>
<blockquote>
<ol>
<li>copy_from_user():将用户空间的数据拷贝到内核空间</li>
<li>copy_to_user():将内核空间的数据拷贝到用户空间</li>
</ol>
</blockquote>
</li>
</ul>
<figure data-type="image" tabindex="2"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/d103f9c5352bb3fec41d063bd4e935d6-linux%E8%BF%9B%E7%A8%8B%E7%A9%BA%E9%97%B4-e559ed.png" alt="linux进程空间" loading="lazy"></figure>
<h4 id="进程隔离-跨进程通信-ipc">进程隔离 & 跨进程通信( IPC )</h4>
<ul>
<li>
<p>进程隔离</p>
<blockquote>
<p>为了保证 安全性 & 独立性,一个进程 不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的</p>
</blockquote>
</li>
<li>
<p>跨进程通信( IPC )</p>
<blockquote>
<p>即进程间需进行数据交互、通信</p>
</blockquote>
</li>
<li>
<p>跨进程通信的基本原理</p>
</li>
</ul>
<figure data-type="image" tabindex="3"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/061dff9688cb48d2f1fbb6a3d2e0b038-%E8%B7%A8%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86-98ac4b.svg" alt="跨进程通信基本原理" loading="lazy"></figure>
<h4 id="内存映射mmap">内存映射mmap</h4>
<p><code>mmap</code>是一种<strong>内存映射文件</strong>的方法,即<strong>将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。</strong> 实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用<code>read</code>,<code>write</code>等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。</p>
<h3 id="binder到底是什么">Binder到底是什么?</h3>
<ul>
<li>中文即 粘合剂,意思为粘合了两个不同的进程</li>
<li>需要从不同的角度去看</li>
</ul>
<figure data-type="image" tabindex="4"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/47a83ac9213dc05510ac96abd35abcde-Binder%E6%98%AF%E4%BB%80%E4%B9%88-6634e3.svg" alt="Binder是什么" loading="lazy"></figure>
<h4 id="binder-跨进程通信机制-模型">Binder 跨进程通信机制 模型</h4>
<ul>
<li>Binder 跨进程通信机制 模型 基于 Client - Server 模式</li>
</ul>
<figure data-type="image" tabindex="5"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/cac5b18e137aa0e0157a7d51dd1a76f3-Binder%E8%B7%A8%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1%E6%9C%BA%E5%88%B6%E6%A8%A1%E5%9E%8B-fd77ab.png" alt="binder_cs.png" loading="lazy"></figure>
<p>模型组成角色说明</p>
<figure data-type="image" tabindex="6"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/a034f6a21009072f7ad7b1acd2c5cf68-Binder%E8%B7%A8%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1%E6%A8%A1%E5%9E%8B%E8%A7%92%E8%89%B2%E8%AF%B4%E6%98%8E-87985d.png" alt="binder_proc.png" loading="lazy"></figure>
<h4 id="binder驱动的作用-原理">Binder驱动的作用 & 原理</h4>
<figure data-type="image" tabindex="7"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/01d62af6f5ce296329782cae1b99a40d-Binder%E9%A9%B1%E5%8A%A8-4d23b0.svg" alt="Binder驱动.svg" loading="lazy"></figure>
<ul>
<li>跨进程通信的核心原理</li>
</ul>
<figure data-type="image" tabindex="8"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/2f8331d74a12e7ce9869c1f126450a16-Binder%E9%80%9A%E4%BF%A1%E7%9A%84%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86-f552dc.png" alt="binder_work.png" loading="lazy"></figure>
<ul>
<li>模型原理步骤说明</li>
</ul>
<figure data-type="image" tabindex="9"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/0750bc30e4595f0a396d77d72b5ae039-Binder%E6%A0%B8%E5%BF%83%E9%80%9A%E4%BF%A1%E6%A8%A1%E5%9E%8B%E5%8E%9F%E7%90%86%E6%AD%A5%E9%AA%A4%E8%AF%B4%E6%98%8E-e42259.png" alt="binder_work_liucheng.png" loading="lazy"></figure>
<h4 id="注意">注意</h4>
<p>说明1:Client进程、Server进程 & Service Manager 进程之间的交互 都必须通过Binder驱动(使用 open 和 ioctl文件操作函数),而非直接交互 原因:</p>
<ol>
<li>Client进程、Server进程 & Service Manager进程属于进程空间的用户空间,不可进行进程间交互</li>
<li>Binder驱动 属于 进程空间的 内核空间,可进行进程间 & 进程内交互</li>
</ol>
<p>所以,原理图可表示为以下:</p>
<blockquote>
<p>虚线表示并非直接交互</p>
</blockquote>
<figure data-type="image" tabindex="10"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/8d1394e3d34347df5f25b8edeadcb97f-Binder%E4%BA%A4%E4%BA%92%E5%8E%9F%E7%90%86%E5%9B%BE-ce3e7f.png" alt="binder_yuanli.png" loading="lazy"></figure>
<p>说明2: Binder驱动 & Service Manager进程 属于 Android基础架构(即系统已经实现好了);而Client 进程 和 Server 进程 属于Android应用层(需要开发者自己实现) 所以,在进行跨进程通信时,开发者只需自定义Client & Server 进程 并 显式使用上述3个步骤,最终借助 Android的基本架构功能就可完成进程间通信</p>
<figure data-type="image" tabindex="11"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/f39430084d6be6162454436eb499376d-Android%E6%9E%B6%E6%9E%84binder%E9%80%9A%E4%BF%A1%E5%9B%BE-da3449.png" alt="binder_yuanli1.png" loading="lazy"></figure>
<p>说明3:Binder请求的线程管理 Server进程会创建很多线程来处理Binder请求 Binder模型的线程管理 采用Binder驱动的线程池,并由Binder驱动自身进行管理</p>
<blockquote>
<p>而不是由Server进程来管理的</p>
</blockquote>
<p>一个进程的Binder线程数默认最大是16,超过的请求会被阻塞等待空闲的Binder线程。</p>
<blockquote>
<p>所以,在进程间通信时处理并发问题时,如使用ContentProvider时,它的CRUD(创建、检索、更新和删除)方法只能同时有16个线程同时工作</p>
</blockquote>
<h3 id="binder机制-在android中的具体实现原理">Binder机制 在Android中的具体实现原理</h3>
<figure data-type="image" tabindex="12"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/27/96134364cd18b64284736fb7976c2322-Binder%E6%9C%BA%E5%88%B6%E5%9C%A8Android%E4%B8%AD%E7%9A%84%E5%85%B7%E4%BD%93%E5%8E%9F%E7%90%86-020a3f.webp" alt="java_binder.webp" loading="lazy"></figure>
<ul>
<li>IMyService接口由 AIDL 文件生成;</li>
<li>Stub 和 Proxy 则是IMyService的内部类,分别是 Binder 类和 BinderProxy 类的子类(Proxy 类虽然是用组合方式来持有 BinderProxy 的,但实际就是在直接用这个类,只不过做了一层封装,让其更易使用而已),Stub 和 Proxy 都实现了 IMyService;</li>
<li>IMyService是一个用于表达 Service 提供的功能的一个契约,也就是说 IInterface 里有的方法,Service 都能提供,调用者你别管用的是 BinderProxy 还是什么,只要拿到 IInterface,你就可以直接调用里面的方法,它就是一个接口;</li>
<li>同时 Stub 虽然实现了 IMyService,但是并没有实现厘米的任何方法,它是一个抽象类,开发者需要自己子类化 Stub 去实现具体的功能;</li>
<li>Proxy 实现了 IMyService,并且实现了里面的方法;</li>
<li>为什么 IMyService 要分 Stub 和 Proxy 呢?这是为了要适用于本地调用和远程调用两种情况。如果 Service 运行在同一个进程,那就直接用 Stub,因为它直接实现了 Service 提供的功能,不需要任何 IPC 过程。如果 Service 运行在其他进程,那客户端使用的就是 Proxy,这里这个 Proxy 的功能大家应该能想到了吧,就是把参数封装后发送给 Binder 驱动,然后执行一系列 IPC 操作最后再取出结果返回。</li>
<li>Stub 是继承自 Binder 并重写了onTransact函数,这个函数三个重要参数:int code、Parcel data、Parcel reply,分别对应了被调函数编号、参数包、响应包。当 Proxy 发起了一个请求,服务端中相应的响应线程就会通过 JNI 调用到 Stub 类,然后执行里面的 execTransact 方法,进而转到 onTransact 方法。</li>
</ul>
<h3 id="为什么android-要使用-binder">为什么Android 要使用 Binder ?</h3>
<p>Android 系统是基于 Linux 内核的,Linux 已经提供了管道、消息队列、共享内存和 Socket 等 IPC 机制。那为什么 Android 还要提供 Binder 来实现 IPC 呢?主要是基于性能、稳定性和安全性几方面的原因。</p>
<h4 id="性能">性能</h4>
<ol>
<li>Socket 作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。</li>
<li>消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。</li>
<li>共享内存虽然无需拷贝,但控制复杂,难以使用。Binder 只需要一次数据拷贝,性能上仅次于共享内存。</li>
</ol>
<table>
<thead>
<tr>
<th>IPC方式</th>
<th style="text-align:center">数据拷贝次数</th>
</tr>
</thead>
<tbody>
<tr>
<td>共享内存</td>
<td style="text-align:center">0</td>
</tr>
<tr>
<td>Binder</td>
<td style="text-align:center">1</td>
</tr>
<tr>
<td>Socket/管道/消息队列</td>
<td style="text-align:center">2</td>
</tr>
</tbody>
</table>
<h4 id="稳定性">稳定性</h4>
<p>Binder 基于 C/S 架构,客户端(Client)有什么需求就丢给服务端(Server)去完成,架构清晰、职责明确又相互独立,自然稳定性更好。共享内存虽然无需拷贝,但是控制负责,难以使用。从稳定性的角度讲,Binder 机制是优于内存共享的。</p>
<h4 id="安全性">安全性</h4>
<p>Android 作为一个开放性的平台,市场上有各类海量的应用供用户选择安装,因此安全性对于 Android 平台而言极其重要。</p>
<ol>
<li>传统的 IPC 接收方无法获得对方可靠的进程用户ID/进程ID(UID/PID),从而无法鉴别对方身份。Android 为每个安装好的 APP 分配了自己的 UID,故而进程的 UID 是鉴别进程身份的重要标志。</li>
<li>传统的 IPC 只能由用户在数据包中填入 UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标识只有由 IPC 机制在内核中添加。</li>
<li>传统的 IPC 访问接入点是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。同时 Binder 既支持实名 Binder,又支持匿名 Binder,安全性高。</li>
</ol>
<p>基于上述原因,Android 需要建立一套新的 IPC 机制来满足系统对稳定性、传输性能和安全性方面的要求,这就是 Binder。</p>
<table>
<thead>
<tr>
<th>优势</th>
<th style="text-align:center">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>性能</td>
<td style="text-align:center">只需要一次数据拷贝,性能上仅次于共享内存</td>
</tr>
<tr>
<td>稳定性</td>
<td style="text-align:center">基于C/S架构,职责明确、架构清晰,因此稳定性好</td>
</tr>
<tr>
<td>安全性</td>
<td style="text-align:center">为每个App分配UID,进程的UID是鉴别进程身份的重要标志</td>
</tr>
</tbody>
</table>
<h3 id="binder-通信中的代理模式">Binder 通信中的代理模式</h3>
<p>我们已经解释清楚 Client、Server 借助 Binder 驱动完成跨进程通信的实现机制了,但是还有个问题会让我们困惑。A 进程想要 B 进程中某个对象(object)是如何实现的呢?毕竟它们分属不同的进程,A 进程 没法直接使用 B 进程中的 object。</p>
<p>前面我们介绍过跨进程通信的过程都有 Binder 驱动的参与,因此在数据流经 Binder 驱动的时候驱动会对数据做一层转换。当 A 进程想要获取 B 进程中的 object 时,驱动并不会真的把 object 返回给 A,而是返回了一个跟 object 看起来一模一样的代理对象 objectProxy,这个 objectProxy 具有和 object 一摸一样的方法,但是这些方法并没有 B 进程中 object 对象那些方法的能力,这些方法只需要把把请求参数交给驱动即可。对于 A 进程来说和直接调用 object 中的方法是一样的。</p>
<p>当 Binder 驱动接收到 A 进程的消息后,发现这是个 objectProxy 就去查询自己维护的表单,一查发现这是 B 进程 object 的代理对象。于是就会去通知 B 进程调用 object 的方法,并要求 B 进程把返回结果发给自己。当驱动拿到 B 进程的返回结果后就会转发给 A 进程,一次通信就完成了。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[AIDL文件编写及源码分析]]></title>
<id>https://jxiaow.gitee.io/posts/40026fc8/</id>
<link href="https://jxiaow.gitee.io/posts/40026fc8/">
</link>
<updated>2021-01-30T14:38:06.000Z</updated>
<content type="html"><![CDATA[<h2 id="aidl编写">AIDL编写</h2>
<p>Binder被用来实现进程间的通信,基本使用步骤如下:</p>
<ol>
<li>创建AIDL文件,编写接口方法;</li>
<li>如果有自定义的model对象,则在aidl下创建包名一致且名称与model名一致的aidl文件;</li>
<li>make project</li>
<li>编写相应的代码,启动服务发送和接收数据。</li>
</ol>
<p>具体操作:</p>
<p><strong>以下例子来源于 <a href="https://gitee.com/jxiaow/practiseCodeAndroid/tree/master/FrameWork/BinderSample">FrameWork/BinderSample</a></strong></p>
<h3 id="创建model对象">创建model对象</h3>
<p><code>Person</code> 实现 <code>Parcelable</code> 接口 (如果不需要自定义model,则不需要)</p>
<pre><code class="language-java">package com.github.jxiaow.sample.model;
import android.os.Parcel;
import android.os.Parcelable;
public class Personal implements Parcelable {
public String name;
public int age;
public Personal(String name, int age) {
this.name = name;
this.age = age;
}
// .....
}
</code></pre>
<h3 id="创建aidl文件">创建AIDL文件</h3>
<p>如果有自定义model对象并且与AIDL接口文件的包名不一致时需要创建一个<code>AIDL</code>文件表示</p>
<pre><code class="language-java">// IPersonal.aidl
// 包名必须与model的一致
package com.github.jxiaow.sample.model;
// Declare any non-default types here with import statements
// 自定义的model需要使用parcelable进行声明
parcelable Personal;
</code></pre>
<p>编写AIDL接口文件</p>
<pre><code class="language-java">// ILeoAidl.aidl
package com.github.jxiaow.sample;
// Declare any non-default types here with import statements
// 导入model对应的aidl文件
import com.github.jxiaow.sample.model.IPersonal;
interface IPersonalAidlInterface {
// 自己定义的model 需要添加in修饰
void addPersonal(in Personal person);
List<Personal> getPersonalList();
}
</code></pre>
<h3 id="make-project">make project</h3>
<p>通过Android studio 的 make project 后生成java版本的aidl接口类。代码结构:</p>
<figure data-type="image" tabindex="1"><img src="https://cdn.jsdelivr.net/gh/jxiaow/cdn-images@latest/blog-images/2021/01/28/0e5e4f7da463171b64417ed0ba4492d8-image-20210128112830363-ea556a.png" alt="image-20210128112830363" loading="lazy"></figure>
<p>生成的重要部分代码如下:</p>
<pre><code class="language-java">package com.github.jxiaow.sample;
public interface IPersonalAidlInterface extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
* Stub 用于数据服务接收端,该抽象方法由服务接收端实现
* 通过asInterface 返回一个proxy给数据发送端
*/
public static abstract class Stub extends android.os.Binder
implements com.github.jxiaow.sample.IPersonalAidlInterface {
// 通过该字段区分binder
private static final java.lang.String DESCRIPTOR =
"com.github.jxiaow.sample.IPersonalAidlInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.github.jxiaow.sample.IPersonalAidlInterface interface,
* generating a proxy if needed.
*/
public static com.github.jxiaow.sample.IPersonalAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
// 如果服务端和客户端不在同一进程,那么obj.queryLocalInterface(DESCRIPTOR)为null
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.github.jxiaow.sample.IPersonalAidlInterface))) {
return ((com.github.jxiaow.sample.IPersonalAidlInterface) iin);
}
// 返回一个服务端代理,用于客户端远程调用服务端的方法
return new com.github.jxiaow.sample.IPersonalAidlInterface.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
// onTransact 复写了Binder中的onTransact
// 客户端调用代理执行相应的方法后会调用到服务端的此方法上进行相应的方法调用
// 数据发送端proxy调用transact后通过binder会调用stub的onTransact
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_addPersonal: {
data.enforceInterface(descriptor);
com.github.jxiaow.sample.model.Personal _arg0;
if ((0 != data.readInt())) {
_arg0 = com.github.jxiaow.sample.model.Personal.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addPersonal(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getPersonalList: {
data.enforceInterface(descriptor);
java.util.List<com.github.jxiaow.sample.model.Personal> _result = this.getPersonalList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
// 代理静态内部类,用于发送数据到服务端
private static class Proxy implements com.github.jxiaow.sample.IPersonalAidlInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void addPersonal(com.github.jxiaow.sample.model.Personal person)
throws android.os.RemoteException {
// _data 是发送的数据
// _reply 接收的数据
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person != null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
// mRemote.transact方法会调用到服务端的onTransact,然后进行方法标记分发
boolean _status = mRemote.transact(Stub.TRANSACTION_addPersonal, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addPersonal(person);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public java.util.List<com.github.jxiaow.sample.model.Personal> getPersonalList()
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.github.jxiaow.sample.model.Personal> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonalList, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getPersonalList();
}
_reply.readException();
_result = _reply.createTypedArrayList(com.github.jxiaow.sample.model.Personal.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.github.jxiaow.sample.IPersonalAidlInterface sDefaultImpl;
}
// 每个方法的标志
static final int TRANSACTION_addPersonal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPersonalList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
// 此方法有继承自Stub的子类实现
public void addPersonal(com.github.jxiaow.sample.model.Personal person)
throws android.os.RemoteException;
public java.util.List<com.github.jxiaow.sample.model.Personal> getPersonalList()
throws android.os.RemoteException;
}
</code></pre>
<h3 id="客户端使用">客户端使用</h3>
<pre><code class="language-java">// 8.0 以后,不允许service后台运行,所以如果将service至于后台,bindService会报错
// W/ActivityManager: Unable to start service Intent
// { cmp=com.github.jxiaow.binderservice/.MyService } U=0: not found
val intent = Intent()
intent.setClassName(
"com.github.jxiaow.binderservice",
"com.github.jxiaow.binderservice.MyService"
)
bindService(intent, conn, Context.BIND_AUTO_CREATE)
</code></pre>
<p>通过asInterface 获取使用。</p>
<pre><code class="language-java">private val conn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
Log.d("Personal", "onServiceConnected: ")
personalInterface = IPersonalAidlInterface.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName) {
personalInterface = null
}
}
</code></pre>
<h2 id="源码分析流程">源码分析流程</h2>
<blockquote>
<p>源码基于API 30</p>
</blockquote>
<h3 id="activitybindservice">Activity#bindService</h3>
<p>在<code>Acitivity</code>中绑定或启动<code>Service</code>时,经常会使用下面的方式,我们就以下面的方式进行源码调用分析。</p>
<pre><code class="language-kotlin">val intent = Intent(this, PersonalService::class.java)
bindService(intent, conn, Context.BIND_AUTO_CREATE)
</code></pre>
<h3 id="contextwrapperbindservice">ContextWrapper#bindService</h3>
<pre><code class="language-java">@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
return mBase.bindService(service, conn, flags);
}
</code></pre>
<p>以上方法中调用了<code>mBase.bindService</code>,而我们可以知道<code>mBase</code>就是<code>ContextImpl</code>的实例。</p>
<h3 id="contextimplbindservice">ContextImpl#bindService</h3>
<pre><code class="language-java">@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null, getUser());
}
</code></pre>
<h3 id="contextimplbindservicecommon">ContextImpl#bindServiceCommon</h3>
<p><code>bindServiceCommon</code>通过<code>ActivityManagerService</code>进行<code>Service</code>的相关操作。</p>
<pre><code class="language-java">private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
// ....
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
// 重点, 此处调用了ActivityManagerService中的方法
// 用于service的相关生命周期处理
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
</code></pre>
<h3 id="activitymanagergetservice">ActivityManager#getService</h3>
<pre><code class="language-java">// 获取一个IActivityManager AIDL接口实现proxy实例
// 由于android 8.0 采用的AIDL模板生成代码的方式,无法在Andorid Studio中看到生成的代码Proxy
// 返回一个单例 ActivityMangerService的Binder代理类
@UnsupportedAppUsage
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
// 通过ServiceManager获取IActivityManager服务端(ActivityManagerService)的代理类
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
// 通过Stub.asInterface 获取AIDL接口生成代码中的proxy实例
// 此处获取的就是AIDL中的proxy, 如果有疑问,去看一下前面的创建AIDL文件处的代码
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
</code></pre>
<p>具体的解析,请看上面代码中的注释,<code>ActivityManager.getService()</code>获取到的是一个<code>IActivityManagerService</code>的代理类。</p>
<pre><code class="language-java">public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback{}
</code></pre>
<h3 id="activitymanagerservicebindisolatedservice">ActivityManagerService#bindIsolatedService</h3>
<pre><code class="language-java">public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection,
int flags, String instanceName,
String callingPackage, int userId)
throws TransactionTooLargeException {
// ....
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
</code></pre>
<h3 id="activieservicebindservicelocked">ActivieService#bindServiceLocked</h3>
<p>如果service已经存在则直接绑定,如果不存在则先创建然后再绑定</p>
<pre><code class="language-java">int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
// ....
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
// 获取Service信息缓存(serivceInfo),如果缓存不存在则创建
// 如果启动一个未启动的service,那么此处是没有缓存的
// 如果启动的是一个已经启动了的service,那么缓存是存在的
ServiceLookupResult res =
retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;
final long origId = Binder.clearCallingIdentity();
try {
// ....
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
// 创建和绑定service
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
// 由于service的创建最终是通过handler转发的,那么创建的时间一般情况下会晚于下面的代码执行
// b.intent.received 未执行绑定操作时,默认情况下是 false, publishService中置为true
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
// 调用的是ServiceDispatcher中的相关方法间接调用onServiceConnection
c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortInstanceName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
// b.intnet.doRebind 默认是false
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
// 检查是否需要重新绑定
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
}
// 默认是false,绑定成功后为true,
// 如果bringUpServiceLocked能执行到realStartService中,则b.intent.requested = true
else if (!b.intent.requested) {
// 请求绑定service
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
}
// ...
return 1;
}
</code></pre>
<h3 id="activieservicebringupservicelocked">ActivieService#bringUpServiceLocked</h3>
<p><code>bringUpServiceLocked</code>中 先判断<code>service</code>是否已经创建,如果创建调用<code>sendServiceArgsLocked</code>方法进行相关操作,否则</p>
<p>调用<code>realStartServiceLocked</code>进行<code>service</code>创建和绑定。</p>
<pre><code class="language-java">private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
// 如果service已经启动调用sendServiceArgsLocked方法通过远程服务执行onStartCommon
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
// ....
// 判断每次启动Service时是否需要独立开启一个进程,此属性是通过 android:isolatedProcess="false" 设置
// 默认false
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
// 启动服务的app是否为null
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
// 重点, 创建并绑定service
// 此方法
realStartServiceLocked(r, app, execInFg);
return null;
}
// ...
}
}
// ....
return null;
}
</code></pre>
<h3 id="activieservicesendserviceargslocked">ActivieService#sendServiceArgsLocked</h3>
<pre><code class="language-java">private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
// r.pendingStarts在service执行完onStartCommon后为空
// 在startServiceLocked中添加service到pendingStarts中 (startService方式启动service)
// 在realStartServiceLocked中也会添加 (bindService 方式启动service)
final int N = r.pendingStarts.size();
// 此处可以判断可以说明 onStartCommon只会执行一次
if (N == 0) {
return;
}
// ...
ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
slice.setInlineCountLimit(4);
Exception caughtException = null;
try {
// 调用 applicationThread中的scheduleServiceArgs
r.app.thread.scheduleServiceArgs(r, slice);
}
// ...
}
</code></pre>
<h3 id="acitivieservicerealstartservicelocked">AcitivieService#realStartServiceLocked</h3>
<p><code>realStartServiceLocked</code>方法中主要完成了2件事:1. 在<code>ApplicationThread</code>中调用<code>scheduleCreateService</code>进行 Service的创建;2. 请求绑定Service。</p>
<pre><code class="language-java">private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
// ....
boolean created = false;
try {
//....
// app.thread ===> ApplicationThread
// 1. AplicationThread 创建Service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
}
// ....
// 2. 请求绑定Service
requestServiceBindingsLocked(r, execInFg);
// 3. 如果是startService方式,service恢复时调用onStartCommon方法
// 正好验证了bindService() 不会调用onStartCommon方法
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
sendServiceArgsLocked(r, execInFg, true);
}
</code></pre>
<h3 id="activitythreadhandlecreateservice">ActivityThread#handleCreateService</h3>
<p>在<code>AcitivieService#realStartServiceLocked()</code>中调用<code>ApplicationThread#scheduleCreateService</code>后,<code>scheduleCreateService</code> 通过Handler发送what为<code>CREATE_SERVICE</code>的事件,然后在会调用<code>ActivityThread#handlerCreateService</code>进行Service 创建。</p>
<pre><code class="language-java">// 创建Service
@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
// 反射创建
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
}
try {
// ....
// 调用service的onCreate
service.onCreate();
mServices.put(data.token, service);
// ...
} catch (Exception e) {
// ....
}
}
</code></pre>
<h3 id="activitythreadhandlebindservice">ActivityThread#handleBindService</h3>
<p>在<code>AcitivieService#realStartServiceLocked</code>中Service创建成功后,会调用<code>requestServiceBindingsLocked</code>进行Service的绑定,最终调用到<code>ActivityThread#handleBindService</code>。</p>
<pre><code class="language-java">// 绑定Service
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
// ...
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
// onBind方法返回binder
IBinder binder = s.onBind(data.intent);
// 调用activityManagerService 的publishService
// 调用ServiceConnection的conn
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
// 重新绑定
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
// ....
}
}
}
</code></pre>
<h3 id="activitymanagerservicepublishservice">ActivityManagerService#publishService</h3>
<pre><code class="language-java">public void publishService(IBinder token, Intent intent, IBinder service) {
// ...
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
</code></pre>
<h3 id="activeservicespublishservicelocked">ActiveServices#publishServiceLocked</h3>
<ol>
<li>通过<code>intent</code>进行过滤获取<code>IntentBindRecord</code>并对<code>request</code>、<code>received</code>赋值为true;</li>
<li>遍历<code>connections</code>,调用<code>c.conn.connected</code>。</li>
</ol>
<pre><code class="language-java">void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
// 通过intent过滤获取IntentBindRecord
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
// ...
try {
c.conn.connected(r.name, service, false);
} catch (Exception e) {
// ...
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
</code></pre>
<h3 id="contextimplbindservicecommon-2">ContextImpl#bindServiceCommon</h3>
<p>前面对<code>service</code>启动和绑定的分析完毕后,在来看看是如何回调<code>ServiceConnection</code>的相关方法的。</p>
<pre><code class="language-java">private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
....
if (mPackageInfo != null) {
if (executor != null) {
// IServiceConnection 来源
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
}
} else {
throw new RuntimeException("Not supported in system context");
}
....
}
</code></pre>
<h3 id="loadapkgetservicedispatchercommon">LoadApk#getServiceDispatcherCommon</h3>
<p>创建<code>ServiceDispatcher</code>(对ServiceConnect实例进行包装和增强)。</p>
<pre><code class="language-java">private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
Context context, Handler handler,
Executor executor, int flags) {
synchronized (mServices) {
....
if (sd == null) {
if (executor != null) {
sd = new ServiceDispatcher(c, context, executor, flags);
} else {
sd = new ServiceDispatcher(c, context, handler, flags);
}
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler, executor);
}
return sd.getIServiceConnection();
}
}
</code></pre>
<pre><code class="language-java">@UnsupportedAppUsage
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
// connection的实际类型
mIServiceConnection = new InnerConnection(this);
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mActivityExecutor = null;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
</code></pre>
<h3 id="innerconnection">InnerConnection</h3>
<p><code>InnerConnection</code>继承自 <code>AIDL</code>中生成的<code>Stub</code>类。</p>
<pre><code class="language-java">private static class InnerConnection extends IServiceConnection.Stub {
@UnsupportedAppUsage
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {