-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
1112 lines (1073 loc) · 241 KB
/
search.xml
File metadata and controls
1112 lines (1073 loc) · 241 KB
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"?>
<search>
<entry>
<title>Android Camera 格式</title>
<url>/post/69b727d7.html</url>
<content><![CDATA[<p>Andriod Camera 推荐使用YUV格式,在Camera API1 中,推荐使用 NV21 和 YV12,因为这两种格式支持所有的Camera设备。<br>在Camera API2 中,推荐试用 YUV_420_888</p>
<h1 id="YUV简介"><a href="#YUV简介" class="headerlink" title="YUV简介"></a>YUV简介</h1><p>不同于RGB颜色模型,使用R,G,B三个颜色分量来表示颜色。YUV使用明亮度”Y”, 色度”U,V”来表示颜色。<br>其中明亮度”Y”(Luninance或Luma)就是我们常见的灰度值, 色度(Chrominance或Chroma)用于指定像素的颜色。<br>其中:U(Cb), 代表蓝色; V(Cr), 代表红色。所有YUV还有一种说法就是YCbCr</p>
<p>YUV的优点:</p>
<ol>
<li>优化彩色视频信号传输,可以很方便的兼容老式黑白电视。黑白电视只需要处理Y分量,彩色在其基础上加上U(Cb), V(Cr)两个分量即可。</li>
<li>降低传输的数据量,以常见的YUV420来看,每4个Y共用一组UV分量给,一个YUV占用 8+2+2 = 12bits = 1.5Byte;而RGB需要8+8+8 = 24bits = 3Byte;节省了一半的数据。</li>
</ol>
<h1 id="常用的格式"><a href="#常用的格式" class="headerlink" title="常用的格式"></a>常用的格式</h1><ul>
<li><p>YUV420SP</p>
<ul>
<li><p>NV21</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">YYYYYYYY VUVU</span><br></pre></td></tr></table></figure></li>
<li><p>NV12</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">YYYYYYYY UVUV</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<ul>
<li><p>YUV420P 平面模式, Y,U,V分别在不同的平面,是标准的4:2:0</p>
<ul>
<li><p>YV12</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">YYYYYYYY VVUU</span><br></pre></td></tr></table></figure></li>
<li><p>I420(YU12)</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">YYYYYYYY UUVV</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<h1 id="内存布局"><a href="#内存布局" class="headerlink" title="内存布局"></a>内存布局</h1><p>在实际使用中,一个YUV420图像大小,往往会比按照图像宽高计算的来的大。主要的原因就是一个数据对齐。这里有下面几个概念:</p>
<ul>
<li>width 图像宽度</li>
<li>rowStride 跨度,图像实际存储的宽度 </li>
<li>height 图像高度</li>
<li>scanLines 扫描线。图像实际存储高度</li>
</ul>
<p>在Android手机的Camera框架中,HAL层的Buffer,都是通过<code>GraphicBufferMapper</code>去分配处理的。我们调用<code>GraphicBufferMapper</code>的lock接口去获取<code>GraphicBuffer</code>时,传入的参数是图像的宽高,返回的实际内存大小是经过对齐后的。</p>
<h2 id="高通-NV12"><a href="#高通-NV12" class="headerlink" title="高通 NV12"></a>高通 NV12</h2><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">/* Venus NV12:</span></span><br><span class="line"><span class="comment"> * YUV 4:2:0 image with a plane of 8 bit Y samples followed</span></span><br><span class="line"><span class="comment"> * by an interleaved U/V plane containing 8 bit 2x2 subsampled</span></span><br><span class="line"><span class="comment"> * colour difference samples.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <-------- Y/UV_Stride --------></span></span><br><span class="line"><span class="comment"> * <------- Width -------></span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . V</span></span><br><span class="line"><span class="comment"> * U V U V U V U V U V U V . . . . ^</span></span><br><span class="line"><span class="comment"> * U V U V U V U V U V U V . . . . |</span></span><br><span class="line"><span class="comment"> * U V U V U V U V U V U V . . . . |</span></span><br><span class="line"><span class="comment"> * U V U V U V U V U V U V . . . . UV_Scanlines</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . V</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . --> Buffer size alignment</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Y_Stride : Width aligned to 128</span></span><br><span class="line"><span class="comment"> * UV_Stride : Width aligned to 128</span></span><br><span class="line"><span class="comment"> * Y_Scanlines: Height aligned to 32</span></span><br><span class="line"><span class="comment"> * UV_Scanlines: Height/2 aligned to 16</span></span><br><span class="line"><span class="comment"> * Extradata: Arbitrary (software-imposed) padding</span></span><br><span class="line"><span class="comment"> * Total size = align((Y_Stride * Y_Scanlines</span></span><br><span class="line"><span class="comment"> * + UV_Stride * UV_Scanlines</span></span><br><span class="line"><span class="comment"> * + max(Extradata, Y_Stride * 8), 4096)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="高通NV21"><a href="#高通NV21" class="headerlink" title="高通NV21"></a>高通NV21</h2><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">/* Venus NV21:</span></span><br><span class="line"><span class="comment"> * YUV 4:2:0 image with a plane of 8 bit Y samples followed</span></span><br><span class="line"><span class="comment"> * by an interleaved V/U plane containing 8 bit 2x2 subsampled</span></span><br><span class="line"><span class="comment"> * colour difference samples.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <-------- Y/UV_Stride --------></span></span><br><span class="line"><span class="comment"> * <------- Width -------></span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |</span></span><br><span class="line"><span class="comment"> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . V</span></span><br><span class="line"><span class="comment"> * V U V U V U V U V U V U . . . . ^</span></span><br><span class="line"><span class="comment"> * V U V U V U V U V U V U . . . . |</span></span><br><span class="line"><span class="comment"> * V U V U V U V U V U V U . . . . |</span></span><br><span class="line"><span class="comment"> * V U V U V U V U V U V U . . . . UV_Scanlines</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . |</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . V</span></span><br><span class="line"><span class="comment"> * . . . . . . . . . . . . . . . . --> Padding & Buffer size alignment</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Y_Stride : Width aligned to 128</span></span><br><span class="line"><span class="comment"> * UV_Stride : Width aligned to 128</span></span><br><span class="line"><span class="comment"> * Y_Scanlines: Height aligned to 32</span></span><br><span class="line"><span class="comment"> * UV_Scanlines: Height/2 aligned to 16</span></span><br><span class="line"><span class="comment"> * Extradata: Arbitrary (software-imposed) padding</span></span><br><span class="line"><span class="comment"> * Total size = align((Y_Stride * Y_Scanlines</span></span><br><span class="line"><span class="comment"> * + UV_Stride * UV_Scanlines</span></span><br><span class="line"><span class="comment"> * + max(Extradata, Y_Stride * 8), 4096)</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>Android</category>
<category>Framework</category>
<category>Camera</category>
</categories>
<tags>
<tag>Android</tag>
<tag>Camera</tag>
<tag>Camera2</tag>
<tag>CameraService</tag>
</tags>
</entry>
<entry>
<title>Android Camera 深度解析</title>
<url>/post/31ae23dc.html</url>
<content><![CDATA[<p>这是一个系列的文章,主要从HAL层,Framework层,应用层三个方面来刨析Android Camera框架的实现原理和设计理念。源码以AOSP android 11版本为例。主要参考Android官网的文档。</p>
<p>这里我会从上到下依次按层级的方式,以Camera2 API和HAL3来解读Android Camera 的源码,中间回掺杂一些额外的补充知识点。</p>
<p>首先看下SDK中的相关内容</p>
<h2 id="相关的类"><a href="#相关的类" class="headerlink" title="相关的类"></a>相关的类</h2><p>在Camera API2 中,主要用到以下几个Package/类</p>
<ul>
<li>Package: android.hardware.camera2</li>
<li>Camera: API1的接口</li>
<li>SurfaceView: 处理预览,渲染的呈现</li>
<li>MediaRecorder: 用于录像</li>
<li>Intent: 提供<code>MediaStore.ACTION_IMAGE_CAPTURE</code> 或者 <code>MediaStore.ACTION_VIDEO_CAPTURE</code> 的Intent操作类型用于捕获图像或者视频,不需要直接使用Camera对象</li>
</ul>
<h2 id="清单声明"><a href="#清单声明" class="headerlink" title="清单声明"></a>清单声明</h2><h3 id="权限申请"><a href="#权限申请" class="headerlink" title="权限申请"></a>权限申请</h3><ul>
<li><p>相机权限</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.CAMERA"</span> /></span></span><br></pre></td></tr></table></figure>
<p>使用现有相机来打开相机(Intent),不需要申请权限</p>
</li>
<li><p>存储权限</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.WRITE_EXTERNAL_STORAGE"</span> /></span></span><br></pre></td></tr></table></figure></li>
<li><p>录音权限</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.RECORD_AUDIO"</span> /></span></span><br></pre></td></tr></table></figure></li>
<li><p>位置权限</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.ACCESS_FINE_LOCATION"</span> /></span></span><br><span class="line">...</span><br><span class="line"><span class="comment"><!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --></span></span><br><span class="line"><span class="tag"><<span class="name">uses-feature</span> <span class="attr">android:name</span>=<span class="string">"android.hardware.location.gps"</span> /></span></span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="功能声明"><a href="#功能声明" class="headerlink" title="功能声明"></a>功能声明</h3><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">uses-feature</span> <span class="attr">android:name</span>=<span class="string">"android.hardware.camera"</span> /></span></span><br></pre></td></tr></table></figure>
<p>非必需情况</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><uses-feature android:name="android.hardware.camera" android:required="false" /></span><br></pre></td></tr></table></figure>
<h2 id="开发相机应用"><a href="#开发相机应用" class="headerlink" title="开发相机应用"></a>开发相机应用</h2><p>在官方开发文档中,建议开发者使用Camera X来开发相机应用。</p>
<p>参考:<br><a href="https://developer.android.com/guide/topics/media/camera">https://developer.android.com/guide/topics/media/camera</a></p>
<p><a href="https://developer.android.com/training/camera2">https://developer.android.com/training/camera2</a></p>
]]></content>
<categories>
<category>Android</category>
<category>Framework</category>
<category>Camera</category>
</categories>
<tags>
<tag>Android</tag>
<tag>Camera</tag>
<tag>Camera2</tag>
<tag>CameraService</tag>
</tags>
</entry>
<entry>
<title>Android Create Platform Keystore for AndroidStudio</title>
<url>/post/a94712d2.html</url>
<content><![CDATA[<p>有时候我们需要在AndroidStudio中开发Android系统应用(带系统签名),为了方便开发,我们一般会生成一个debug.keystore,以下是操作步骤</p>
<h3 id="找到系统源码的key"><a href="#找到系统源码的key" class="headerlink" title="找到系统源码的key"></a>找到系统源码的key</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">cd build/target/product/security/</span><br></pre></td></tr></table></figure>
<h3 id="生成pem文件"><a href="#生成pem文件" class="headerlink" title="生成pem文件"></a>生成pem文件</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out shared.priv.pem -nocrypt</span><br></pre></td></tr></table></figure>
<h3 id="生成pk12文件"><a href="#生成pk12文件" class="headerlink" title="生成pk12文件"></a>生成pk12文件</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">openssl pkcs12 -export -in platform.x509.pem -inkey shared.priv.pem -out shared.pk12 -name youralias</span><br></pre></td></tr></table></figure>
<h3 id="设置密码"><a href="#设置密码" class="headerlink" title="设置密码"></a>设置密码</h3><ul>
<li>默认密码是android</li>
<li>可以自己修改</li>
</ul>
<h3 id="生成keystore"><a href="#生成keystore" class="headerlink" title="生成keystore"></a>生成keystore</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">keytool -importkeystore -deststorepass android -destkeypass android -destkeystore debug.keystore -srckeystore shared.pk12 -srcstoretype PKCS12 -srcstorepass android -alias youralias</span><br></pre></td></tr></table></figure>
<h3 id="总共会生成以下三个文件,其中debug-keystore就是我们需要的"><a href="#总共会生成以下三个文件,其中debug-keystore就是我们需要的" class="headerlink" title="总共会生成以下三个文件,其中debug.keystore就是我们需要的"></a>总共会生成以下三个文件,其中debug.keystore就是我们需要的</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">shared.pk12</span><br><span class="line">shared.priv.pem</span><br><span class="line">debug.keystore</span><br></pre></td></tr></table></figure>
<h3 id="部署到AndroidStudio"><a href="#部署到AndroidStudio" class="headerlink" title="部署到AndroidStudio"></a>部署到AndroidStudio</h3><p>可以参考之前的文章<a href="/post/66cda814.html" title="AndroidStudio Gradle 全局参数配置">AndroidStudio Gradle 全局参数配置</a></p>
]]></content>
<categories>
<category>Android</category>
<category>Platform</category>
<category>keystore</category>
</categories>
<tags>
<tag>Android</tag>
<tag>Keystore</tag>
<tag>AndroidStudio</tag>
</tags>
</entry>
<entry>
<title>Android Segmentation Demo Based on TFLite</title>
<url>/post/1ce7ae9a.html</url>
<content><![CDATA[<p><a href="https://www.tensorflow.org/lite">TFLite</a> 是Google基于TensorFlow 推出的移动端深度学习工具。我们可以利用这个工具,将训练好的模型部署到移动端设备上,支持(Android和iOS).</p>
<h3 id="如何应用"><a href="#如何应用" class="headerlink" title="如何应用"></a>如何应用</h3><h4 id="选择模型"><a href="#选择模型" class="headerlink" title="选择模型"></a><a href="https://www.tensorflow.org/lite/devguide#1_choose_a_model">选择模型</a></h4><h4 id="转换成TFLite模型"><a href="#转换成TFLite模型" class="headerlink" title="转换成TFLite模型"></a><a href="https://www.tensorflow.org/lite/devguide#2_convert_the_model_format">转换成TFLite模型</a></h4><p>利用TensorFlow官方提供的转换工具,可以建多种不同类型的模型,转换成TFLite支持的模型。目前支持</p>
<ol>
<li>tf.GraphDef (.pb or .pbtxt)</li>
<li>tf.keras (.h5)</li>
</ol>
<h4 id="部署到移动端设备上"><a href="#部署到移动端设备上" class="headerlink" title="部署到移动端设备上"></a><a href="https://www.tensorflow.org/lite/devguide#3_use_the_tensorflow_lite_model_for_inference_in_a_mobile_app">部署到移动端设备上</a></h4><p>将生成的.tflite模型部署到移动端或者嵌入式设备上。</p>
<h4 id="优化模型"><a href="#优化模型" class="headerlink" title="优化模型"></a><a href="https://www.tensorflow.org/lite/devguide#4_optimize_your_model_optional">优化模型</a></h4><p>通过量化方式,将32位浮点型转换成更有效的8位整型,或者在移动端的GPU上运行。</p>
<h3 id="实例分割Demo"><a href="#实例分割Demo" class="headerlink" title="实例分割Demo"></a>实例分割Demo</h3><h4 id="下载Google提供的GPU版本DeeplabV3-tflite模型"><a href="#下载Google提供的GPU版本DeeplabV3-tflite模型" class="headerlink" title="下载Google提供的GPU版本DeeplabV3 tflite模型"></a>下载Google提供的GPU版本DeeplabV3 tflite模型</h4><p><a href="https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/deeplabv3_257_mv_gpu.tflite">下载地址</a></p>
<ol>
<li>输入</li>
<li>输出</li>
</ol>
<h4 id="参考TensorFlow-examples"><a href="#参考TensorFlow-examples" class="headerlink" title="参考TensorFlow examples"></a>参考<a href="https://github.com/tensorflow/examples">TensorFlow examples</a></h4><p>里面提供了多种类型的Demo,支持各个平台</p>
<h3 id="开启GPU支持"><a href="#开启GPU支持" class="headerlink" title="开启GPU支持"></a><a href="https://www.tensorflow.org/lite/performance/gpu_advanced">开启GPU支持</a></h3><ol>
<li>Module Gradle 依赖需要使用nightly版本<figure class="highlight gradle"><table><tr><td class="code"><pre><span class="line"><span class="keyword">repositories</span> {</span><br><span class="line"> maven {</span><br><span class="line"> url <span class="string">'https://google.bintray.com/tensorflow'</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">dependencies</span> {</span><br><span class="line"> implementation <span class="keyword">fileTree</span>(dir: <span class="string">'libs'</span>, <span class="keyword">include</span>: [<span class="string">'*.jar'</span>])</span><br><span class="line"> <span class="comment">/** ... **/</span></span><br><span class="line"> implementation <span class="string">'org.tensorflow:tensorflow-lite:0.0.1-gpu-experimental'</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
<li>Java 代码中开启支持<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// NEW: Prepare GPU delegate.</span></span><br><span class="line">GpuDelegate delegate = <span class="keyword">new</span> GpuDelegate();</span><br><span class="line">Interpreter.Options options = (<span class="keyword">new</span> Interpreter.Options()).addDelegate(delegate);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Set up interpreter.</span></span><br><span class="line">Interpreter interpreter = <span class="keyword">new</span> Interpreter(model, options);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Run inference.</span></span><br><span class="line">writeToInputTensor(inputTensor);</span><br><span class="line">interpreter.run(inputTensor, outputTensor);</span><br><span class="line">readFromOutputTensor(outputTensor);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Clean up.</span></span><br><span class="line">delegate.close();</span><br></pre></td></tr></table></figure></li>
</ol>
]]></content>
<categories>
<category>Android</category>
<category>Application</category>
<category>TFLite</category>
</categories>
<tags>
<tag>Android</tag>
<tag>TFlite</tag>
<tag>Segmentation</tag>
</tags>
</entry>
<entry>
<title>Android 后台任务之 IntentService</title>
<url>/post/2fa13cac.html</url>
<content><![CDATA[<p>IntentService 是Android SDK中引入的一个非常好用的,有效的单线程后台任务工具</p>
<h2 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h2><ul>
<li>不影响UI响应</li>
<li>不受生命周期影响</li>
</ul>
<h2 id="限制"><a href="#限制" class="headerlink" title="限制"></a>限制</h2><ul>
<li>不能和UI直接交互</li>
<li>任务顺序运行,一次只能运行一个任务</li>
<li>不能被中断</li>
</ul>
<h2 id="创建方式"><a href="#创建方式" class="headerlink" title="创建方式"></a>创建方式</h2><ol>
<li>继承IntentService类</li>
<li>提供一个默认的构造函数</li>
<li>实现<code>onHandleIntent(Intent workIntent)</code>来处理后台任务</li>
<li>在Manifest文件中声明</li>
</ol>
<h2 id="使用IntentService"><a href="#使用IntentService" class="headerlink" title="使用IntentService"></a>使用IntentService</h2><ol>
<li>创建一个Intent,将任务数据用Intent发送给IntentService</li>
<li>调用<code>startService(Intent workIntent)</code>启动<code>IntentService</code></li>
</ol>
<h2 id="如何将IntentService处理完的数据返回到Activity"><a href="#如何将IntentService处理完的数据返回到Activity" class="headerlink" title="如何将IntentService处理完的数据返回到Activity"></a>如何将IntentService处理完的数据返回到Activity</h2><ol>
<li>使用<code>LocalBroadcastManager</code>,任务完成后,通过广播把数据用Intent返回到Activity</li>
</ol>
<h2 id="Demo"><a href="#Demo" class="headerlink" title="Demo"></a>Demo</h2><p>假设用后台服务来获取天气信息</p>
<ul>
<li><p><code>WeatherFetchService.java</code></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WeatherFetchService</span> <span class="keyword">extends</span> <span class="title">IntentService</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">"WeatherFetchService"</span>;</span><br><span class="line"> <span class="keyword">private</span> Random random;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">WeatherFetchService</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>(TAG);</span><br><span class="line"> random = <span class="keyword">new</span> Random();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onHandleIntent</span><span class="params">(Intent intent)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(intent == <span class="keyword">null</span>){</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> String city = intent.getStringExtra(Constants.CITY_NAME);</span><br><span class="line"> <span class="comment">// Simulate weather information.</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">2000</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Return result.</span></span><br><span class="line"> <span class="keyword">int</span> t = random.nextInt(<span class="number">100</span>);</span><br><span class="line"> intent.setAction(Constants.ACTION_WEATHER_RESULT);</span><br><span class="line"> intent.putExtra(Constants.TEMPERATURE, t);</span><br><span class="line"> LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
<li><p><code>MainActivity.java</code></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> BroadcastReceiver weatherResultReceiver;</span><br><span class="line"> <span class="keyword">private</span> TextView temperature;</span><br><span class="line"> <span class="keyword">private</span> EditText city;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_main);</span><br><span class="line"> city = findViewById(R.id.city);</span><br><span class="line"> temperature = findViewById(R.id.temperature);</span><br><span class="line"> findViewById(R.id.refresh).setOnClickListener(<span class="keyword">this</span>);</span><br><span class="line"> findViewById(R.id.clear).setOnClickListener(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"> weatherResultReceiver = <span class="keyword">new</span> BroadcastReceiver() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onReceive</span><span class="params">(Context context, Intent intent)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(intent == <span class="keyword">null</span>){</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> String action = intent.getAction();</span><br><span class="line"> <span class="keyword">if</span>(Constants.ACTION_WEATHER_RESULT.equals(action)){</span><br><span class="line"> <span class="keyword">int</span> temp = intent.getIntExtra(Constants.TEMPERATURE,Constants.TEMPERATURE_DEFAULT);</span><br><span class="line"> temperature.setText(String.valueOf(temp));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> IntentFilter intentFilter = <span class="keyword">new</span> IntentFilter();</span><br><span class="line"> intentFilter.addAction(Constants.ACTION_WEATHER_RESULT);</span><br><span class="line"></span><br><span class="line"> LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(weatherResultReceiver, intentFilter);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>{</span><br><span class="line"> LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(weatherResultReceiver);</span><br><span class="line"> <span class="keyword">super</span>.onDestroy();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> id = v.getId();</span><br><span class="line"> <span class="keyword">switch</span> (id){</span><br><span class="line"> <span class="keyword">case</span> R.id.refresh:</span><br><span class="line"> String cityName = city.getText().toString();</span><br><span class="line"> Intent intent = <span class="keyword">new</span> Intent(MainActivity.<span class="keyword">this</span>, WeatherFetchService.class);</span><br><span class="line"> intent.putExtra(Constants.CITY_NAME, cityName);</span><br><span class="line"> startService(intent);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> R.id.clear:</span><br><span class="line"> city.setText(<span class="string">""</span>);</span><br><span class="line"> temperature.setText(<span class="string">""</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul>
<li><a href="https://developer.android.com/guide/components/services">https://developer.android.com/guide/components/services</a></li>
<li><a href="https://developer.android.com/training/run-background-service/send-request">https://developer.android.com/training/run-background-service/send-request</a></li>
<li><a href="https://developer.android.com/training/run-background-service/report-status">https://developer.android.com/training/run-background-service/report-status</a></li>
</ul>
]]></content>
<categories>
<category>Android</category>
<category>Application</category>
<category>Service</category>
</categories>
<tags>
<tag>Android</tag>
<tag>Background Tasks</tag>
<tag>IntentService</tag>
</tags>
</entry>
<entry>
<title>AndroidStudio Gradle 全局参数配置</title>
<url>/post/66cda814.html</url>
<content><![CDATA[<h2 id="先提出以下两个问题"><a href="#先提出以下两个问题" class="headerlink" title="先提出以下两个问题"></a>先提出以下两个问题</h2><ul>
<li><strong>在开发Android应用时,如何将配置参数应用到所有的AndroidStudio项目中?</strong></li>
<li><strong>有些敏感信息我们不希望包含在工程中,跟随代码提交,比如签名相关信息。</strong></li>
</ul>
<h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>我们可以利用Gradle的全局配置文件,为我们所有的项目配置相关参数,解决以上两个问题。</p>
<ul>
<li>Windows平台在 <code>C:\Users\user\.gradle</code> 目录下</li>
<li>Linux平台在 <code>/home/user/.gradle</code> 目录下</li>
<li>Mac平台类似,找到<code>gradle</code>的目录即可</li>
</ul>
<h3 id="下面以配置签名信息为例:"><a href="#下面以配置签名信息为例:" class="headerlink" title="下面以配置签名信息为例:"></a>下面以配置签名信息为例:</h3><ol>
<li>打开<code>gradle.properties</code>文件,在文件末尾增加如下信息:<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">KEYSTOREFILE=../../keystore/android.keystore</span><br><span class="line">KEYALIAS=release</span><br><span class="line">KEYPASSWORD=helloworld</span><br><span class="line">STOREPASSWORD=helloworld</span><br></pre></td></tr></table></figure></li>
</ol>
<ul>
<li><strong>注意</strong><ul>
<li>这里的配置信息是没有<code>""</code>双引号的,有引号会导致异常。</li>
<li><code>KEYSOTREFILE</code>使用的是相对目录,相对于<code>app/build.gradle</code>文件所在的目录。</li>
<li>比如我这个文件就位于和工程文件夹相同级别的目录<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">MyProject/app/build.gradle</span><br><span class="line">MyProject1/app/build.gradle</span><br><span class="line">MyProject2/app/build.gradle</span><br><span class="line">MyProject3/app/build.gradle</span><br><span class="line">keystore/android.keystore</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<ol start="2">
<li>在到对应的工程下面,打开app/build.gradle</li>
</ol>
<ul>
<li>增加signingConfigs</li>
<li>在buildTypes release里面增加signConfig配置<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">android {</span><br><span class="line"> compileSdkVersion 28</span><br><span class="line"> defaultConfig {</span><br><span class="line"> applicationId "com.example.test"</span><br><span class="line"> minSdkVersion 21</span><br><span class="line"> targetSdkVersion 28</span><br><span class="line"> versionCode 1</span><br><span class="line"> versionName "1.0"</span><br><span class="line"> testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"</span><br><span class="line"> }</span><br><span class="line"> // 增加签名配置</span><br><span class="line"> signingConfigs{</span><br><span class="line"> releaseConfig{</span><br><span class="line"> keyAlias KEYALIAS //引用刚才配置的参数</span><br><span class="line"> keyPassword KEYPASSWORD</span><br><span class="line"> storePassword STOREPASSWORD</span><br><span class="line"> storeFile file(KEYSTOREFILE)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> buildTypes {</span><br><span class="line"> release {</span><br><span class="line"> signingConfig signingConfigs.releaseConfig //引用配置文件</span><br><span class="line"> minifyEnabled false</span><br><span class="line"> proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
<ol start="3">
<li>这样配置后,即使代码提交了,也不会将签名信息提交,其他开发者把代码拉下来后,只需要到<code>gradle.properties</code>里面配置好对应的参数即可。其他全局配置也可以这么操作。</li>
</ol>
]]></content>
<categories>
<category>Android</category>
<category>AndroidStudio</category>
<category>Gradle</category>
</categories>
<tags>
<tag>AndroidStudio</tag>
<tag>Gradle</tag>
<tag>Tutorial</tag>
</tags>
</entry>
<entry>
<title>Android 后台任务</title>
<url>/post/9dbfc6f1.html</url>
<content><![CDATA[<p>我们知道,在Android应用开发的过程中,不能在主线程中处理耗时任务,否则会导致UI卡顿,甚至ANR,非常影响用户体验,这就需要把这些耗时的任务,转移到后台去运行。</p>
<h2 id="主线程工作"><a href="#主线程工作" class="headerlink" title="主线程工作"></a>主线程工作</h2><ol>
<li>更新UI(包括测量和更新View)</li>
<li>协调用户交互</li>
<li>接收生命周期事件</li>
</ol>
<h2 id="以下操作需要在独立的线程里面"><a href="#以下操作需要在独立的线程里面" class="headerlink" title="以下操作需要在独立的线程里面"></a>以下操作需要在独立的线程里面</h2><ol>
<li>处理图片资源</li>
<li>访问磁盘,读写文件</li>
<li>处理网络请求</li>
<li>任何其他耗时达到几百毫秒的操作</li>
<li>当应用没有运行在前台,并且要在后台同步数据的时候</li>
</ol>
<h2 id="后台应用挑战"><a href="#后台应用挑战" class="headerlink" title="后台应用挑战"></a>后台应用挑战</h2><ol>
<li>后台应用会消耗设备的有限的资源,比如RAM和电池,这个可能会给用户带来不好的体验</li>
<li>为了最大化电池的使用,Android系统会强制限制后台应用程序<ul>
<li>Android 6.0,引入了Doze 和 App standby</li>
<li>Android 7.0,限制隐式广播和引入Doze-on-the-Go</li>
<li>Android 8.0, 限制后台行为,比如定位和Wekelocks</li>
<li>Android 9.0, 引入App Standby Buckets</li>
</ul>
</li>
</ol>
<h2 id="如何选择合适的方案"><a href="#如何选择合适的方案" class="headerlink" title="如何选择合适的方案"></a>如何选择合适的方案</h2><ol>
<li>任务是否可以延迟,还是需要立刻执行?</li>
<li>独立工作还是依赖系统环境?</li>
<li>是否需要精确定时运行?</li>
</ol>
<h2 id="Google推荐的方案"><a href="#Google推荐的方案" class="headerlink" title="Google推荐的方案"></a>Google推荐的方案</h2><ul>
<li>WorkManager<ul>
<li>Android Libraries (API Level 14+)</li>
</ul>
</li>
<li>Forground Service<ul>
<li>告知用户正在处理的重要内容</li>
<li>前台服务是可见的</li>
</ul>
</li>
<li>AlarmManager<ul>
<li>定时任务</li>
</ul>
</li>
<li>DownloadManager<ul>
<li>HTTP长连接</li>
</ul>
</li>
</ul>
<h2 id="具体可以参考下面的流程"><a href="#具体可以参考下面的流程" class="headerlink" title="具体可以参考下面的流程"></a>具体可以参考下面的流程</h2><img src="img/bg-job-choose.svg">
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul>
<li><a href="https://developer.android.com/guide/background/">https://developer.android.com/guide/background/</a></li>
</ul>
]]></content>
<categories>
<category>Android</category>
<category>Application</category>
<category>Service</category>
</categories>
<tags>
<tag>Android</tag>
<tag>Background Tasks</tag>
</tags>
</entry>
<entry>
<title>AndroidStudio OpenCV NDK tutorial</title>
<url>/post/dd932aba.html</url>
<content><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><ul>
<li>OpenCV是目前计算机视觉里面非常常用的一个开源库,支持各大平台</li>
</ul>
<h2 id="准备条件"><a href="#准备条件" class="headerlink" title="准备条件"></a>准备条件</h2><ul>
<li>AndroidStudio 最新版本</li>
<li>SDK Manager里面安装SDK, NDK</li>
<li>OpenCV 3.4/4.0<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">wget https://codeload.github.com/OpenCV/OpenCV/zip/3.4.6</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="准备知识-CMake"><a href="#准备知识-CMake" class="headerlink" title="准备知识-CMake"></a>准备知识-CMake</h2><p>AndroidStudio 支持cmake编译C/C++文件,通过编写CMakeList.txt来实现</p>
<h3 id="常用变量"><a href="#常用变量" class="headerlink" title="常用变量"></a>常用变量</h3><figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">${CMAKE_SOURCE_DIR} <span class="comment"># CMakeLists.txt文件所在位置</span></span><br><span class="line">${ANDROID_ABI} <span class="comment"># Android ABI架构 ("armeabi-v7a","arm64-v8a")</span></span><br></pre></td></tr></table></figure>
<h3 id="常用函数"><a href="#常用函数" class="headerlink" title="常用函数"></a>常用函数</h3><ul>
<li><p>常用指令</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Set project</span></span><br><span class="line">project(demo)</span><br><span class="line"><span class="comment"># Set variable</span></span><br><span class="line">set(VARIABLE, VALUE)</span><br><span class="line"><span class="comment"># Show message</span></span><br><span class="line">message(${ANDROID_ABI})</span><br><span class="line"><span class="comment"># if else</span></span><br><span class="line">if(${ANDROID_ABI} STREQUAL <span class="string">"areambi"</span>)</span><br><span class="line"> message(<span class="string">"armv5"</span>)</span><br><span class="line">elseif(${ANDROID_ABI} STREQUAL <span class="string">"areambi-v7a"</span>)</span><br><span class="line"> message(<span class="string">"armv7a"</span>)</span><br><span class="line">elseif(${ANDROID_ABI} STREQUAL <span class="string">"arm64-v8a"</span>)</span><br><span class="line"> message(<span class="string">"armv8a"</span>)</span><br><span class="line">elseif(${ANDROID_ABI} STREQUAL <span class="string">"x86_64"</span>)</span><br><span class="line"> message(<span class="string">"x86_64"</span>)</span><br><span class="line">elseif(${ANDROID_ABI} STREQUAL <span class="string">"x86"</span>)</span><br><span class="line"> message(<span class="string">"x86"</span>)</span><br><span class="line"><span class="keyword">else</span>()</span><br><span class="line"> message(<span class="string">"unknown abi"</span>)</span><br><span class="line"><span class="keyword">endif</span>()</span><br></pre></td></tr></table></figure></li>
<li><p>添加共享库</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">add_library( </span><br><span class="line"><span class="comment"># Sets the name of the library.</span></span><br><span class="line">native-lib</span><br><span class="line"><span class="comment"># Sets the library as a shared library.</span></span><br><span class="line">SHARED</span><br><span class="line"><span class="comment"># Provides a relative path to your source file(s).</span></span><br><span class="line">src/main/cpp/native-lib.cpp)</span><br></pre></td></tr></table></figure></li>
<li><p>添加可执行文件</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">add_executable( </span><br><span class="line"><span class="comment"># Sets the name of the executable file.</span></span><br><span class="line">test</span><br><span class="line"><span class="comment"># Provides a relative path to your source file(s).</span></span><br><span class="line">src/main/cpp/main.cpp)</span><br></pre></td></tr></table></figure></li>
<li><p>查找NDK library</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Searches for a specified prebuilt library and stores the path as a</span></span><br><span class="line"><span class="comment"># variable. Because CMake includes system libraries in the search path by</span></span><br><span class="line"><span class="comment"># default, you only need to specify the name of the public NDK library</span></span><br><span class="line"><span class="comment"># you want to add. CMake verifies that the library exists before</span></span><br><span class="line"><span class="comment"># completing its build.</span></span><br><span class="line"></span><br><span class="line">find_library( <span class="comment"># Sets the name of the path variable.</span></span><br><span class="line"> log-lib</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Specifies the name of the NDK library that</span></span><br><span class="line"> <span class="comment"># you want CMake to locate.</span></span><br><span class="line"> log)</span><br></pre></td></tr></table></figure></li>
<li><p>指定链接库</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Specifies libraries CMake should link to your target library. You</span></span><br><span class="line"><span class="comment"># can link multiple libraries, such as libraries you define in this</span></span><br><span class="line"><span class="comment"># build script, prebuilt third-party libraries, or system libraries.</span></span><br><span class="line"></span><br><span class="line">target_link_libraries( <span class="comment"># Specifies the target library.</span></span><br><span class="line"> test</span><br><span class="line"> <span class="comment"># Links the target library to the log library</span></span><br><span class="line"> <span class="comment"># included in the NDK.</span></span><br><span class="line"> ${log-lib})</span><br></pre></td></tr></table></figure></li>
<li><p>指定包含头文件</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/<span class="keyword">include</span>/)</span><br><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)</span><br></pre></td></tr></table></figure></li>
<li><p>手动指定共享库</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">add_library(libOpenCV_java3 SHARED IMPORTED)</span><br><span class="line">set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION</span><br><span class="line"> ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.so)</span><br></pre></td></tr></table></figure></li>
<li><p>查找所有源文件,并保存到<code>IR_SRCS</code>变量,但是不能查找子目录</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">aux_source_directory(${CMAKE_SOURCE_DIR}/src/main/cpp DIR_SRCS)</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="编译器设置"><a href="#编译器设置" class="headerlink" title="编译器设置"></a>编译器设置</h3><p>我们可以在CMakeLists.txt里面设置编译器参数,也可以在build.gradle脚本里面设置</p>
<ul>
<li><p>CMakeLists.txt 设置</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line"><span class="comment">#支持-std=gnu++11</span></span><br><span class="line">set(CMAKE_VERBOSE_MAKEFILE on)</span><br><span class="line">set(CMAKE_CXX_FLAGS <span class="string">"${CMAKE_CXX_FLAGS} -std=gnu++11"</span>)</span><br></pre></td></tr></table></figure></li>
<li><p>build.gradle 脚本设置</p>
<figure class="highlight gradle"><table><tr><td class="code"><pre><span class="line">apply plugin: <span class="string">'com.android.application'</span></span><br><span class="line"></span><br><span class="line">android {</span><br><span class="line"> defaultConfig {</span><br><span class="line"> externalNativeBuild {</span><br><span class="line"> cmake {</span><br><span class="line"> <span class="comment">//设置cpp Flags</span></span><br><span class="line"> cppFlags <span class="string">"-std=c++11 -frtti -fexceptions"</span></span><br><span class="line"> <span class="comment">//设置STL共享库,这里要注意,部分Android系统里面可能没有libc++_shared.so,这个时候需要在app里面打包进去</span></span><br><span class="line"> <span class="comment">//文件路径在NDK安装目录下 sources/cxx-stl/llvm-libc++/libs/${ANDROID_ABI}/libc++_shared.so</span></span><br><span class="line"> arguments <span class="string">"-DANDROID_STL=c++_shared"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="输出设置"><a href="#输出设置" class="headerlink" title="输出设置"></a>输出设置</h3><ul>
<li><p>动态共享库 <code>.so</code></p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)</span><br><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/<span class="keyword">include</span>/)</span><br><span class="line">add_library(libOpenCV_java3 SHARED IMPORTED)</span><br><span class="line">set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION</span><br><span class="line"> ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.so)</span><br><span class="line">find_library( <span class="comment"># Sets the name of the path variable.</span></span><br><span class="line"> log-lib</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Specifies the name of the NDK library that</span></span><br><span class="line"> <span class="comment"># you want CMake to locate.</span></span><br><span class="line"> log)</span><br><span class="line">add_library( <span class="comment"># Sets the name of the library.</span></span><br><span class="line"> native-lib</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Sets the library as a shared library.</span></span><br><span class="line"> SHARED</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Provides a relative path to your source file(s).</span></span><br><span class="line"></span><br><span class="line"> src/main/cpp/native-lib.cpp)</span><br><span class="line">target_link_libraries( <span class="comment"># Specifies the target library.</span></span><br><span class="line"> native-lib</span><br><span class="line"> libOpenCV_java3</span><br><span class="line"> <span class="comment"># Links the target library to the log library</span></span><br><span class="line"> <span class="comment"># included in the NDK.</span></span><br><span class="line"> ${log-lib})</span><br></pre></td></tr></table></figure></li>
<li><p>静态共享库 <code>.a</code></p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)</span><br><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/<span class="keyword">include</span>/)</span><br><span class="line">add_library(libOpenCV_java3 SHARED IMPORTED)</span><br><span class="line">set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION</span><br><span class="line"> ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.so)</span><br><span class="line">find_library( <span class="comment"># Sets the name of the path variable.</span></span><br><span class="line"> log-lib</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Specifies the name of the NDK library that</span></span><br><span class="line"> <span class="comment"># you want CMake to locate.</span></span><br><span class="line"> log)</span><br><span class="line">add_library( <span class="comment"># Sets the name of the library.</span></span><br><span class="line"> native-lib</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Sets the library as a static library.</span></span><br><span class="line"> STATIC</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Provides a relative path to your source file(s).</span></span><br><span class="line"></span><br><span class="line"> src/main/cpp/native-lib.cpp)</span><br><span class="line">target_link_libraries( <span class="comment"># Specifies the target library.</span></span><br><span class="line"> native-lib</span><br><span class="line"> libOpenCV_java3</span><br><span class="line"> <span class="comment"># Links the target library to the log library</span></span><br><span class="line"> <span class="comment"># included in the NDK.</span></span><br><span class="line"> ${log-lib})</span><br></pre></td></tr></table></figure></li>
<li><p>Executable</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)</span><br><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/<span class="keyword">include</span>/)</span><br><span class="line">add_library(libOpenCV_java3 SHARED IMPORTED)</span><br><span class="line">set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION</span><br><span class="line"> ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.so)</span><br><span class="line">find_library( <span class="comment"># Sets the name of the path variable.</span></span><br><span class="line"> log-lib</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Specifies the name of the NDK library that</span></span><br><span class="line"> <span class="comment"># you want CMake to locate.</span></span><br><span class="line"> log)</span><br><span class="line"><span class="comment"># 设置可执行文件的输出目录</span></span><br><span class="line">set(EXECUTABLE_OUTPUT_PATH <span class="string">"${CMAKE_SOURCE_DIR}/src/main/assets/${ANDROID_ABI}"</span>)</span><br><span class="line"><span class="comment"># 添加可执行文件的源文件</span></span><br><span class="line">add_executable(</span><br><span class="line"> test</span><br><span class="line"></span><br><span class="line"> src/main/cpp/main.cpp</span><br><span class="line">)</span><br><span class="line">target_link_libraries( <span class="comment"># Specifies the target library.</span></span><br><span class="line"> test</span><br><span class="line"> libOpenCV_java3</span><br><span class="line"> <span class="comment"># Links the target library to the log library</span></span><br><span class="line"> <span class="comment"># included in the NDK.</span></span><br><span class="line"> ${log-lib})</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="依赖设置"><a href="#依赖设置" class="headerlink" title="依赖设置"></a>依赖设置</h3><h3 id="与Gradle结合"><a href="#与Gradle结合" class="headerlink" title="与Gradle结合"></a>与Gradle结合</h3><h2 id="新建Project"><a href="#新建Project" class="headerlink" title="新建Project"></a>新建Project</h2><p>用AndroidStudio创建项目,并选择Native C++支持</p>
<h2 id="导入OpenCV头文件"><a href="#导入OpenCV头文件" class="headerlink" title="导入OpenCV头文件"></a>导入OpenCV头文件</h2><ol>
<li>在<code>src/main/cpp</code>目录下创建<code>include</code>目录</li>
<li>将OpenCV SDK解压后,<code>sdk/native/jni/include/</code>目录下的两个头文件文件夹<code>OpenCV, OpenCV2</code>复制到上面创建的<code>include</code>目录下</li>
<li>CMakeList.txt添加对应引用<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/)</span><br></pre></td></tr></table></figure></li>
</ol>
<h2 id="导入OpenCV-so库"><a href="#导入OpenCV-so库" class="headerlink" title="导入OpenCV so库"></a>导入OpenCV so库</h2><ol>
<li>创建<code>src/main/jniLibs</code>目录,用于存放第三方共享库</li>
<li>将OpenCV SDK解压后,<code>sdk/native/libs/</code>目录下的<code>so</code>文件文件夹复制到上面创建的<code>jniLibs</code>目录下,这些文件夹是以<code>abi</code>为目录保存的。</li>
<li>CMakeList.txt添加对应依赖<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">add_library(libOpenCV_java3 SHARED IMPORTED)</span><br><span class="line">set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION</span><br><span class="line"> ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.so)</span><br></pre></td></tr></table></figure></li>
</ol>
<h2 id="jni引用OpenCV方法"><a href="#jni引用OpenCV方法" class="headerlink" title="jni引用OpenCV方法"></a>jni引用OpenCV方法</h2><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"OpenCV2/core.hpp"</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> cv;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="编译验证"><a href="#编译验证" class="headerlink" title="编译验证"></a>编译验证</h2>]]></content>
<categories>
<category>Android</category>
<category>NDK</category>
<category>OpenCV</category>
</categories>
<tags>
<tag>AndroidStudio</tag>
<tag>Gradle</tag>
<tag>Tutorial</tag>
</tags>
</entry>
<entry>
<title>Convert Keras h5 model to TFLite model</title>
<url>/post/dd926e02.html</url>
<content><![CDATA[<p>目前在移动端(Android)使用比较广泛的深度模型框架是TFLite,这个也是Google大力推广的。但是目前很多高效的网络都没有官方的TensorFlow版本,所以在使用的时候,我们需要将其他格式的模型,转换成TFLite格式。<br>好在Google提供了非常全的转换工具,在最新版本中,Keras已经成为了官方推荐的前端。</p>
<h2 id="模型转换前的准备"><a href="#模型转换前的准备" class="headerlink" title="模型转换前的准备"></a>模型转换前的准备</h2><ul>
<li>确定源模型的格式</li>
<li>确定源模型的输入名称,输入尺寸</li>
<li>确定源模型的输出名称,输出尺寸</li>
</ul>
<h2 id="下面以Yolov3的cfg和weights文件转换成TFLite为例"><a href="#下面以Yolov3的cfg和weights文件转换成TFLite为例" class="headerlink" title="下面以Yolov3的cfg和weights文件转换成TFLite为例"></a>下面以Yolov3的cfg和weights文件转换成TFLite为例</h2><p>Yolo的Backbone是Darknet,首先需要转换成支持的keras模型</p>
<ol>
<li>转换成Keras h5 格式</li>
</ol>
<p>使用修改后的工具<a href="https://github.com/vectoros/keras-yolo3">keras_yolov3</a>, 用里面的convert.py文件,将模型转成keras的h5格式</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">wget https://pjreddie.com/media/files/yolov3.weights</span><br><span class="line">python convert.py yolov3.cfg yolov3.weights <span class="number">320</span> model_data/yolov3.h5</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>读取转换后模型的参数</li>
</ol>
<p>转换模型函数需要提供输出和输出</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_output_names</span>(<span class="params">keras_model</span>):</span></span><br><span class="line"> outputs = keras_model.outputs</span><br><span class="line"> output_names = []</span><br><span class="line"> <span class="keyword">for</span> _output <span class="keyword">in</span> outputs:</span><br><span class="line"> output_names.append(_output.name[:-<span class="number">2</span>])</span><br><span class="line"> <span class="keyword">return</span> output_names</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_input_names</span>(<span class="params">keras_model</span>):</span></span><br><span class="line"> inputs = keras_model.inputs</span><br><span class="line"> input_names = []</span><br><span class="line"> <span class="keyword">for</span> _<span class="built_in">input</span> <span class="keyword">in</span> inputs:</span><br><span class="line"> input_names.append(_<span class="built_in">input</span>.name[:-<span class="number">2</span>])</span><br><span class="line"> <span class="keyword">return</span> input_names</span><br></pre></td></tr></table></figure>
<ol start="3">
<li>使用官方提供的<code>lite.TFLiteConverter.from_keras_model_file</code>转换模型</li>
</ol>
<p>调用官方提供的方法转换模型</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">keras_to_tflite</span>(<span class="params">input_keras_model_file, output_tflite_file</span>):</span></span><br><span class="line"> keras_model = load_model(input_keras_model_file)</span><br><span class="line"> input_names = get_input_names(keras_model)</span><br><span class="line"> output_names = get_output_names(keras_model)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"input names:"</span>, input_names, <span class="string">" shapes:"</span>, keras_model.input_shape)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"output names:"</span>, output_names, <span class="string">" shapes:"</span>, keras_model.output_shape)</span><br><span class="line"> converter = lite.TFLiteConverter.from_keras_model_file(model_file=input_keras_model_file,</span><br><span class="line"> input_arrays=input_names,</span><br><span class="line"> output_arrays=output_names)</span><br><span class="line"> model = converter.convert()</span><br><span class="line"> file = <span class="built_in">open</span>(output_tflite_file, <span class="string">"wb"</span>)</span><br><span class="line"> file.write(model)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"save tflite file to: "</span>, output_tflite_file)</span><br></pre></td></tr></table></figure>
<ol start="4">
<li>获取转换后的模型</li>
</ol>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span>():</span></span><br><span class="line"> keras_model_file = <span class="string">"./model_data/yolov3.h5"</span></span><br><span class="line"> tflite_model_file = <span class="string">"./model_data/yolov3.tflite"</span></span><br><span class="line"> keras_to_tflite(keras_model_file, tflite_model_file)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure>
<h2 id="预告"><a href="#预告" class="headerlink" title="预告"></a>预告</h2><p>如何在PC端验证测试转换后的TFLite模型</p>
]]></content>
<categories>
<category>Python</category>
<category>TensorFlow</category>
<category>Keras</category>
</categories>
<tags>
<tag>Keras</tag>
<tag>TFLite</tag>
</tags>
</entry>
<entry>
<title>Build Tensorflow Lite benchmark for Android</title>
<url>/post/1b1cf1e2.html</url>
<content><![CDATA[<p>我们在部署模型到Android端的时候,需要先评估模型的性能,Tensorflow官方给我们提供了TFLite的benchmark工具</p>
<h1 id="整体流程"><a href="#整体流程" class="headerlink" title="整体流程"></a>整体流程</h1><ol>
<li>准备编译环境</li>
<li>安装依赖项目</li>
<li>安装编译工具</li>
<li>下载tensorflow源码</li>
<li>编译benchmark</li>
<li>部署到Android设备上</li>
<li>运行</li>
</ol>
<h2 id="准备编译环境"><a href="#准备编译环境" class="headerlink" title="准备编译环境"></a>准备编译环境</h2><p>建议用Linux系统,这个部分可以参考<a href="https://www.tensorflow.org/install/source">官方指南</a>, 我这边使用的Ubuntu 18.04</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># install python and prerequisites</span></span><br><span class="line">sudo apt install python-dev python-pip</span><br><span class="line">pip install -U --user pip six numpy wheel mock</span><br><span class="line">pip install -U --user keras_applications==1.0.6 --no-deps</span><br><span class="line">pip install -U --user keras_preprocessing==1.0.5 --no-deps</span><br><span class="line"></span><br><span class="line"><span class="comment"># install openjdk-8</span></span><br><span class="line">sudo apt-get install openjdk-8-jdk</span><br></pre></td></tr></table></figure>
<h2 id="安装编译工具bazel"><a href="#安装编译工具bazel" class="headerlink" title="安装编译工具bazel"></a>安装编译工具<code>bazel</code></h2><p>参考<a href="https://docs.bazel.build/versions/master/install.html">bazel官网</a>,编译最新版本需要bazel版本>=0.24.1</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># install the prerequisites</span></span><br><span class="line">sudo apt-get install pkg-config zip g++ zlib1g-dev unzip python</span><br><span class="line"></span><br><span class="line"><span class="comment"># download bazel from github</span></span><br><span class="line"><span class="comment"># Next, download the Bazel binary installer named bazel-<version>-installer-linux-x86_64.sh from the Bazel releases page on GitHub.</span></span><br><span class="line">wget https://github.com/bazelbuild/bazel/releases/download/0.24.1/bazel-0.24.1-installer-linux-x86_64.sh</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># run the installer 0.24.1</span></span><br><span class="line">chmod +x bazel-0.24.1-installer-linux-x86_64.sh</span><br><span class="line">./bazel-0.24.1-installer-linux-x86_64.sh --user</span><br><span class="line"></span><br><span class="line"><span class="comment"># setup environment</span></span><br><span class="line"><span class="built_in">export</span> PATH=<span class="string">"<span class="variable">$PATH</span>:<span class="variable">$HOME</span>/bin"</span></span><br></pre></td></tr></table></figure>
<h2 id="安装Android-SDK和NDK"><a href="#安装Android-SDK和NDK" class="headerlink" title="安装Android SDK和NDK"></a>安装Android SDK和NDK</h2><p>编译Android平台的benchmark需要Android SDK和NDK(里面包含Build tools, Platform tools)</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mkdir ~/Android</span><br><span class="line"><span class="built_in">cd</span> Android</span><br><span class="line"><span class="comment"># NDK</span></span><br><span class="line">wget https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip</span><br><span class="line">unzip android-ndk-r17c-linux-x86_64.zip</span><br><span class="line">mkdir Sdk</span><br><span class="line">mv android-ndk-r17c Sdk/ndk-bundle</span><br><span class="line"></span><br><span class="line"><span class="comment"># SDK tools</span></span><br><span class="line">wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip</span><br><span class="line">unzip sdk-tools-linux-4333796.zip </span><br><span class="line">mv tools/ Sdk/</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Platform tools</span></span><br><span class="line">wget https://dl.google.com/android/repository/platform-tools-latest-linux.zip</span><br><span class="line">unzip platform-tools-latest-linux.zip </span><br><span class="line">mv platform-tools Sdk/</span><br><span class="line"></span><br><span class="line"><span class="comment"># Using sdkmanager to install tools</span></span><br><span class="line"><span class="built_in">cd</span> Sdk</span><br><span class="line">chmod a+x tools/bin/sdkmanager</span><br><span class="line">./tools/bin/sdkmanager <span class="string">"platform-tools"</span> <span class="string">"platforms;android-28"</span> <span class="string">"platforms;android-29"</span> <span class="string">"build-tools;29.0.0"</span> </span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="编译tflite-benchmark"><a href="#编译tflite-benchmark" class="headerlink" title="编译tflite benchmark"></a>编译tflite benchmark</h2><p>参考<a href="https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark">官方文档</a></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># download tensorflow code</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/tensorflow/tensorflow.git</span><br><span class="line"></span><br><span class="line"><span class="comment"># build benchmark for android</span></span><br><span class="line">bazel build -c opt \</span><br><span class="line"> --config=android_arm \</span><br><span class="line"> --cxxopt=<span class="string">'--std=c++11'</span> \</span><br><span class="line"> tensorflow/lite/tools/benchmark:benchmark_model</span><br><span class="line"></span><br><span class="line"><span class="comment"># build benchmark for desktop</span></span><br><span class="line">bazel build -c opt --cxxopt=<span class="string">'--std=c++11'</span> tensorflow/lite/tools/benchmark:benchmark_model</span><br></pre></td></tr></table></figure>
<h2 id="在Android上运行"><a href="#在Android上运行" class="headerlink" title="在Android上运行"></a>在Android上运行</h2><p>编译好的benchmark_model是一个Android平台的可运行的二进制文件,可以在adb shell里面直接运行</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">adb push bazel-bin/tensorflow/lite/tools/benchmark/benchmark_model /data/<span class="built_in">local</span>/tmp</span><br><span class="line"></span><br><span class="line">adb shell chmod +x /data/<span class="built_in">local</span>/tmp/benchmark_model</span><br><span class="line"></span><br><span class="line">adb push mobilenet_v2_1.0_224_quant.tflite /data/<span class="built_in">local</span>/tmp</span><br><span class="line"></span><br><span class="line">/data/<span class="built_in">local</span>/tmp/benchmark_model \</span><br><span class="line"> --graph=/data/<span class="built_in">local</span>/tmp/mobilenet_v2_1.0_224_quant.tflite \</span><br><span class="line"> --num_threads=10</span><br><span class="line"></span><br><span class="line"><span class="comment"># tashset f0 是 Pixel系列手机上,让程序运行在Big core上的命令</span></span><br><span class="line">adb shell taskset f0 /data/<span class="built_in">local</span>/tmp/benchmark_model \</span><br><span class="line"> --graph=/data/<span class="built_in">local</span>/tmp/mobilenet_v2_1.0_224_quant.tflite \</span><br><span class="line"> --enable_op_profiling=<span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h2 id="运行结果"><a href="#运行结果" class="headerlink" title="运行结果"></a>运行结果</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># mobilenet</span></span><br><span class="line">taskset f0 /data/<span class="built_in">local</span>/tmp/benchmark_model \</span><br><span class="line"> --graph=/data/<span class="built_in">local</span>/tmp/mobilenet_v2_1.0_224_quant.tflite \</span><br><span class="line"> --enable_op_profiling=<span class="literal">true</span></span><br><span class="line"></span><br><span class="line">STARTING!</span><br><span class="line">Min num runs: [50]</span><br><span class="line">Min runs duration (seconds): [1]</span><br><span class="line">Inter-run delay (seconds): [-1]</span><br><span class="line">Num threads: [1]</span><br><span class="line">Benchmark name: []</span><br><span class="line">Output prefix: []</span><br><span class="line">Min warmup runs: [1]</span><br><span class="line">Min warmup runs duration (seconds): [0.5]</span><br><span class="line">Graph: [/data/<span class="built_in">local</span>/tmp/mobilenet_v2_1.0_224_quant.tflite]</span><br><span class="line">Input layers: []</span><br><span class="line">Input shapes: []</span><br><span class="line">Use nnapi : [0]</span><br><span class="line">Use legacy nnapi : [0]</span><br><span class="line">Use gpu : [0]</span><br><span class="line">Allow fp16 : [0]</span><br><span class="line">Enable op profiling: [1]</span><br><span class="line">Loaded model /data/<span class="built_in">local</span>/tmp/mobilenet_v2_1.0_224_quant.tflite</span><br><span class="line">resolved reporter</span><br><span class="line">INFO: Initialized TensorFlow Lite runtime.</span><br><span class="line">Initialized session <span class="keyword">in</span> 1.892ms</span><br><span class="line">Running benchmark <span class="keyword">for</span> at least 1 iterations and at least 0.5 seconds</span><br><span class="line">count=6 first=91810 curr=85097 min=84834 max=91810 avg=86184.3 std=2519</span><br><span class="line"></span><br><span class="line">Running benchmark <span class="keyword">for</span> at least 50 iterations and at least 1 seconds</span><br><span class="line">count=50 first=118810 curr=114219 min=88216 max=129193 avg=115062 std=7678</span><br><span class="line"></span><br><span class="line">Average inference timings <span class="keyword">in</span> us: Warmup: 86184.3, Init: 1892, no stats: 115062</span><br><span class="line">============================== Run Order ==============================</span><br><span class="line"> [node <span class="built_in">type</span>] [start] [first] [avg ms] [%] [cdf%] [mem KB] [<span class="built_in">times</span> called] [Name]</span><br><span class="line"> CONV_2D 0.000 5.567 7.237 6.297% 6.297% 0.000 1 [MobilenetV2/Conv/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 7.241 3.518 3.726 3.243% 9.539% 0.000 1 [MobilenetV2/expanded_conv/depthwise/Relu6]</span><br><span class="line"> CONV_2D 10.971 2.399 3.711 3.229% 12.768% 0.000 1 [MobilenetV2/expanded_conv/project/add_fold]</span><br><span class="line"> CONV_2D 14.688 12.247 17.846 15.529% 28.297% 0.000 1 [MobilenetV2/expanded_conv_1/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 32.539 2.594 3.486 3.033% 31.330% 0.000 1 [MobilenetV2/expanded_conv_1/depthwise/Relu6]</span><br><span class="line"> CONV_2D 36.028 1.460 2.462 2.142% 33.472% 0.000 1 [MobilenetV2/expanded_conv_1/project/add_fold]</span><br><span class="line"> CONV_2D 38.493 12.619 7.820 6.805% 40.277% 0.000 1 [MobilenetV2/expanded_conv_2/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 46.318 4.750 3.683 3.205% 43.482% 0.000 1 [MobilenetV2/expanded_conv_2/depthwise/Relu6]</span><br><span class="line"> CONV_2D 50.005 4.853 3.305 2.876% 46.358% 0.000 1 [MobilenetV2/expanded_conv_2/project/add_fold]</span><br><span class="line"> ADD 53.313 0.279 0.293 0.255% 46.613% 0.000 1 [MobilenetV2/expanded_conv_2/add]</span><br><span class="line"> CONV_2D 53.607 12.993 7.827 6.811% 53.424% 0.000 1 [MobilenetV2/expanded_conv_3/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 61.438 2.546 1.647 1.434% 54.857% 0.000 1 [MobilenetV2/expanded_conv_3/depthwise/Relu6]</span><br><span class="line"> CONV_2D 63.089 1.239 1.009 0.878% 55.735% 0.000 1 [MobilenetV2/expanded_conv_3/project/add_fold]</span><br><span class="line"> CONV_2D 64.099 2.261 2.151 1.872% 57.607% 0.000 1 [MobilenetV2/expanded_conv_4/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 66.253 1.251 1.238 1.077% 58.685% 0.000 1 [MobilenetV2/expanded_conv_4/depthwise/Relu6]</span><br><span class="line"> CONV_2D 67.493 1.074 1.126 0.980% 59.665% 0.000 1 [MobilenetV2/expanded_conv_4/project/add_fold]</span><br><span class="line"> ADD 68.621 0.097 0.106 0.092% 59.757% 0.000 1 [MobilenetV2/expanded_conv_4/add]</span><br><span class="line"> CONV_2D 68.728 2.234 2.056 1.789% 61.546% 0.000 1 [MobilenetV2/expanded_conv_5/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 70.786 1.135 1.180 1.027% 62.573% 0.000 1 [MobilenetV2/expanded_conv_5/depthwise/Relu6]</span><br><span class="line"> CONV_2D 71.968 1.073 1.174 1.022% 63.594% 0.000 1 [MobilenetV2/expanded_conv_5/project/add_fold]</span><br><span class="line"> ADD 73.145 0.096 0.098 0.086% 63.680% 0.000 1 [MobilenetV2/expanded_conv_5/add]</span><br><span class="line"> CONV_2D 73.244 1.992 2.172 1.890% 65.570% 0.000 1 [MobilenetV2/expanded_conv_6/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 75.419 0.409 0.469 0.408% 65.978% 0.000 1 [MobilenetV2/expanded_conv_6/depthwise/Relu6]</span><br><span class="line"> CONV_2D 75.889 0.395 0.445 0.387% 66.366% 0.000 1 [MobilenetV2/expanded_conv_6/project/add_fold]</span><br><span class="line"> CONV_2D 76.335 1.277 1.172 1.020% 67.386% 0.000 1 [MobilenetV2/expanded_conv_7/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 77.509 0.778 0.624 0.543% 67.929% 0.000 1 [MobilenetV2/expanded_conv_7/depthwise/Relu6]</span><br><span class="line"> CONV_2D 78.135 1.041 0.779 0.678% 68.606% 0.000 1 [MobilenetV2/expanded_conv_7/project/add_fold]</span><br><span class="line"> ADD 78.915 0.067 0.054 0.047% 68.653% 0.000 1 [MobilenetV2/expanded_conv_7/add]</span><br><span class="line"> CONV_2D 78.969 1.059 1.147 0.998% 69.651% 0.000 1 [MobilenetV2/expanded_conv_8/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 80.118 0.639 0.619 0.539% 70.190% 0.000 1 [MobilenetV2/expanded_conv_8/depthwise/Relu6]</span><br><span class="line"> CONV_2D 80.738 0.620 0.767 0.667% 70.857% 0.000 1 [MobilenetV2/expanded_conv_8/project/add_fold]</span><br><span class="line"> ADD 81.506 0.052 0.051 0.044% 70.902% 0.000 1 [MobilenetV2/expanded_conv_8/add]</span><br><span class="line"> CONV_2D 81.558 1.271 1.139 0.991% 71.892% 0.000 1 [MobilenetV2/expanded_conv_9/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 82.699 0.595 0.582 0.506% 72.399% 0.000 1 [MobilenetV2/expanded_conv_9/depthwise/Relu6]</span><br><span class="line"> CONV_2D 83.282 0.853 0.750 0.652% 73.051% 0.000 1 [MobilenetV2/expanded_conv_9/project/add_fold]</span><br><span class="line"> ADD 84.033 0.055 0.053 0.046% 73.097% 0.000 1 [MobilenetV2/expanded_conv_9/add]</span><br><span class="line"> CONV_2D 84.087 1.078 1.127 0.981% 74.078% 0.000 1 [MobilenetV2/expanded_conv_10/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 85.216 0.635 0.595 0.518% 74.596% 0.000 1 [MobilenetV2/expanded_conv_10/depthwise/Relu6]</span><br><span class="line"> CONV_2D 85.813 1.022 1.106 0.963% 75.559% 0.000 1 [MobilenetV2/expanded_conv_10/project/add_fold]</span><br><span class="line"> CONV_2D 86.921 2.031 2.034 1.770% 77.328% 0.000 1 [MobilenetV2/expanded_conv_11/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 88.957 0.999 0.980 0.852% 78.181% 0.000 1 [MobilenetV2/expanded_conv_11/depthwise/Relu6]</span><br><span class="line"> CONV_2D 89.939 1.476 1.588 1.382% 79.562% 0.000 1 [MobilenetV2/expanded_conv_11/project/add_fold]</span><br><span class="line"> ADD 91.529 0.074 0.077 0.067% 79.629% 0.000 1 [MobilenetV2/expanded_conv_11/add]</span><br><span class="line"> CONV_2D 91.607 2.472 2.057 1.790% 81.419% 0.000 1 [MobilenetV2/expanded_conv_12/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 93.666 1.046 0.959 0.834% 82.253% 0.000 1 [MobilenetV2/expanded_conv_12/depthwise/Relu6]</span><br><span class="line"> CONV_2D 94.627 1.548 1.564 1.361% 83.614% 0.000 1 [MobilenetV2/expanded_conv_12/project/add_fold]</span><br><span class="line"> ADD 96.193 0.077 0.079 0.068% 83.683% 0.000 1 [MobilenetV2/expanded_conv_12/add]</span><br><span class="line"> CONV_2D 96.272 2.107 2.032 1.768% 85.451% 0.000 1 [MobilenetV2/expanded_conv_13/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 98.306 0.318 0.319 0.278% 85.729% 0.000 1 [MobilenetV2/expanded_conv_13/depthwise/Relu6]</span><br><span class="line"> CONV_2D 98.626 0.717 0.732 0.637% 86.365% 0.000 1 [MobilenetV2/expanded_conv_13/project/add_fold]</span><br><span class="line"> CONV_2D 99.359 1.280 1.413 1.230% 87.595% 0.000 1 [MobilenetV2/expanded_conv_14/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 100.774 0.332 0.364 0.316% 87.911% 0.000 1 [MobilenetV2/expanded_conv_14/depthwise/Relu6]</span><br><span class="line"> CONV_2D 101.142 1.191 1.238 1.077% 88.989% 0.000 1 [MobilenetV2/expanded_conv_14/project/add_fold]</span><br><span class="line"> ADD 102.382 0.037 0.039 0.034% 89.023% 0.000 1 [MobilenetV2/expanded_conv_14/add]</span><br><span class="line"> CONV_2D 102.421 1.305 1.459 1.270% 90.292% 0.000 1 [MobilenetV2/expanded_conv_15/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 103.883 0.369 0.391 0.340% 90.633% 0.000 1 [MobilenetV2/expanded_conv_15/depthwise/Relu6]</span><br><span class="line"> CONV_2D 104.275 1.214 1.239 1.078% 91.711% 0.000 1 [MobilenetV2/expanded_conv_15/project/add_fold]</span><br><span class="line"> ADD 105.516 0.036 0.036 0.032% 91.743% 0.000 1 [MobilenetV2/expanded_conv_15/add]</span><br><span class="line"> CONV_2D 105.552 1.312 1.405 1.222% 92.965% 0.000 1 [MobilenetV2/expanded_conv_16/expand/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 106.960 0.352 0.401 0.349% 93.314% 0.000 1 [MobilenetV2/expanded_conv_16/depthwise/Relu6]</span><br><span class="line"> CONV_2D 107.362 2.322 2.311 2.011% 95.325% 0.000 1 [MobilenetV2/expanded_conv_16/project/add_fold]</span><br><span class="line"> CONV_2D 109.675 3.883 3.400 2.958% 98.283% 0.000 1 [MobilenetV2/Conv_1/Relu6]</span><br><span class="line"> AVERAGE_POOL_2D 113.078 0.129 0.125 0.109% 98.392% 0.000 1 [MobilenetV2/Logits/AvgPool]</span><br><span class="line"> CONV_2D 113.204 1.732 1.844 1.604% 99.996% 0.000 1 [MobilenetV2/Logits/Conv2d_1c_1x1/BiasAdd]</span><br><span class="line"> RESHAPE 115.050 0.005 0.005 0.004% 100.000% 0.000 1 [output]</span><br><span class="line"></span><br><span class="line">============================== Top by Computation Time ==============================</span><br><span class="line"> [node <span class="built_in">type</span>] [start] [first] [avg ms] [%] [cdf%] [mem KB] [<span class="built_in">times</span> called] [Name]</span><br><span class="line"> CONV_2D 14.688 12.247 17.846 15.529% 15.529% 0.000 1 [MobilenetV2/expanded_conv_1/expand/Relu6]</span><br><span class="line"> CONV_2D 53.607 12.993 7.827 6.811% 22.340% 0.000 1 [MobilenetV2/expanded_conv_3/expand/Relu6]</span><br><span class="line"> CONV_2D 38.493 12.619 7.820 6.805% 29.145% 0.000 1 [MobilenetV2/expanded_conv_2/expand/Relu6]</span><br><span class="line"> CONV_2D 0.000 5.567 7.237 6.297% 35.442% 0.000 1 [MobilenetV2/Conv/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 7.241 3.518 3.726 3.243% 38.684% 0.000 1 [MobilenetV2/expanded_conv/depthwise/Relu6]</span><br><span class="line"> CONV_2D 10.971 2.399 3.711 3.229% 41.913% 0.000 1 [MobilenetV2/expanded_conv/project/add_fold]</span><br><span class="line"> DEPTHWISE_CONV_2D 46.318 4.750 3.683 3.205% 45.118% 0.000 1 [MobilenetV2/expanded_conv_2/depthwise/Relu6]</span><br><span class="line"> DEPTHWISE_CONV_2D 32.539 2.594 3.486 3.033% 48.151% 0.000 1 [MobilenetV2/expanded_conv_1/depthwise/Relu6]</span><br><span class="line"> CONV_2D 109.675 3.883 3.400 2.958% 51.109% 0.000 1 [MobilenetV2/Conv_1/Relu6]</span><br><span class="line"> CONV_2D 50.005 4.853 3.305 2.876% 53.985% 0.000 1 [MobilenetV2/expanded_conv_2/project/add_fold]</span><br><span class="line"></span><br><span class="line">Number of nodes executed: 65</span><br><span class="line">============================== Summary by node <span class="built_in">type</span> ==============================</span><br><span class="line"> [Node <span class="built_in">type</span>] [count] [avg ms] [avg %] [cdf %] [mem KB] [<span class="built_in">times</span> called]</span><br><span class="line"> CONV_2D 36 92.625 80.619% 80.619% 0.000 36</span><br><span class="line"> DEPTHWISE_CONV_2D 17 21.256 18.501% 99.120% 0.000 17</span><br><span class="line"> ADD 10 0.882 0.768% 99.888% 0.000 10</span><br><span class="line"> AVERAGE_POOL_2D 1 0.125 0.109% 99.997% 0.000 1</span><br><span class="line"> RESHAPE 1 0.004 0.003% 100.000% 0.000 1</span><br><span class="line"></span><br><span class="line">Timings (microseconds): count=50 first=118487 curr=113927 min=88158 max=129072 avg=114924 std=7657</span><br><span class="line">Memory (bytes): count=0</span><br><span class="line">65 nodes observed</span><br></pre></td></tr></table></figure>
<h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><ol>
<li>C++11编译异常</li>
</ol>
<p>bazel编译命令后,加上<code>--cxxopt='--std=c++11'</code> 选项</p>
<ol start="2">
<li>Bazel版本过低或者过高</li>
</ol>
<p>安装0.24.1版本的bazel</p>
]]></content>
<categories>
<category>Android</category>
<category>Tensorflow</category>
<category>TFLite</category>
<category>Benchmark</category>
</categories>
<tags>
<tag>Android</tag>
<tag>TFLite</tag>
</tags>
</entry>
<entry>
<title>Convert Yolov3 cfg and weights files to keras h5 model</title>
<url>/post/c17fb91d.html</url>
<content><![CDATA[<p>Yolov3 是一个非常有效的用于目标检查的One-Stage模型,Backbone使用的是Darknet53,在平时用Keras比较多,所以想将其cfg和weights与训练权重转换成Keras的h5模型,在Github上找寻了一番,发现<a href="https://github.com/qqwweee/keras-yolo3">keras-yolo3</a>这个工具非常有效,故基于此项目做了一定的修改<a href="https://github.com/vectoros/keras-yolo3">keras_yolov3</a>。</p>
<h2 id="修改点:增加了对模型输入尺寸的自定义"><a href="#修改点:增加了对模型输入尺寸的自定义" class="headerlink" title="修改点:增加了对模型输入尺寸的自定义"></a>修改点:增加了对模型输入尺寸的自定义</h2><p>原作的input size是未定义的输入尺寸,默认为416,为了使得转换模型更加灵活</p>
<ul>
<li>将input size作为转换的输入参数</li>
<li>input size必须是32的整数倍</li>
</ul>
<h2 id="如何界定输出的Tensor大小"><a href="#如何界定输出的Tensor大小" class="headerlink" title="如何界定输出的Tensor大小"></a>如何界定输出的Tensor大小</h2><p>仔细阅读论文,你会发现,输出的tensor尺寸和输入的tensor尺寸是相关联的,具体如下</p>
<ul>
<li><code>outputs[0].shape = [input_size / 32, input_size / 32, (num_classes + 5) * 3] </code></li>
<li><code>outputs[1].shape = [input_size * 2 / 32, input_size * 2 / 32, (num_classes + 5) * 3] </code></li>
<li><code>outputs[2].shape = [input_size * 4 / 32, input_size * 4 / 32, (num_classes + 5) * 3] </code></li>
</ul>
<p>这个数据在后续转换为其他如TFLite的时候非常有用</p>
]]></content>
<categories>
<category>Object Dection</category>
<category>TensorFlow</category>
<category>Keras</category>
<category>TFLite</category>
</categories>
<tags>
<tag>Keras</tag>
<tag>TFLite</tag>
<tag>Yolov3</tag>
<tag>TensorFlow</tag>
</tags>
</entry>
<entry>
<title>Compiler OpenCV under the NDK toolchain</title>
<url>/post/af4251a0.html</url>
<content><![CDATA[<h2 id="为什么要手动编译OpenCV"><a href="#为什么要手动编译OpenCV" class="headerlink" title="为什么要手动编译OpenCV"></a>为什么要手动编译OpenCV</h2><p>正常情况下,我们利用OpenCV来开发Android应用,使用预编译的so和jar包已经足够了,但是在某些特殊情形下,我们希望自己编译OpenCV,借此来提高OpenCV的性能。</p>
<h2 id="准备条件"><a href="#准备条件" class="headerlink" title="准备条件"></a>准备条件</h2><ol>
<li>Ubuntu 18.04 64Bit</li>
<li>cmake</li>
<li><a href="https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip">NDK Reversion 17.2.4988734</a></li>
<li><a href="https://opencv.org/releases/">OpenCV 4.0.1</a></li>
<li>Android API</li>
<li>Target armeabi-v7a</li>
</ol>
<h2 id="下载和配置NDK"><a href="#下载和配置NDK" class="headerlink" title="下载和配置NDK"></a>下载和配置NDK</h2><ol>
<li><p>从Google官网下载</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">wget https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip</span><br></pre></td></tr></table></figure></li>
<li><p>下载后解压到特定目录</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">unzip android-ndk-r17c-linux-x86_64.zip</span><br><span class="line">mv android-ndk-r17c /opt/ndk</span><br></pre></td></tr></table></figure></li>
</ol>
<h2 id="下载OpenCV源码"><a href="#下载OpenCV源码" class="headerlink" title="下载OpenCV源码"></a>下载OpenCV源码</h2><ol>
<li><p>从官网下载最新版本或者特定版本</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">unzip opencv.zip</span><br></pre></td></tr></table></figure></li>
<li><p>从Github上下载</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/opencv/opencv.git opencv</span><br></pre></td></tr></table></figure></li>
</ol>
<h2 id="编译OpenCV"><a href="#编译OpenCV" class="headerlink" title="编译OpenCV"></a>编译OpenCV</h2><ol>
<li><p>创建输出目录</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> opencv</span><br><span class="line">$ make build</span><br><span class="line">$ <span class="built_in">cd</span> build</span><br></pre></td></tr></table></figure></li>
<li><p>配置编译规则</p>
<figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line">cmake -DCMAKE_TOOLCHAIN_FILE=/opt/ndk/build/cmake/android.toolchain.cmake \</span><br><span class="line">-DANDROID_NDK=/opt/ndk \</span><br><span class="line">-DANDROID_NATIVE_API_LEVEL=android-<span class="number">21</span> \</span><br><span class="line">-DCMAKE_BUILD_TYPE=Release \</span><br><span class="line">-DENABLE_VFPV3=<span class="keyword">ON</span> \</span><br><span class="line">-DANDROID_ARM_NEON=<span class="keyword">TRUE</span> \</span><br><span class="line">-DENABLE_NEON=<span class="keyword">ON</span> \</span><br><span class="line">-DBUILD_PNG=<span class="keyword">ON</span> \</span><br><span class="line">-DBUILD_JASPER=<span class="keyword">ON</span> \</span><br><span class="line">-DBUILD_JPEG=<span class="keyword">ON</span> \</span><br><span class="line">-DBUILD_TIFF=<span class="keyword">ON</span> \</span><br><span class="line">-DBUILD_ZLIB=<span class="keyword">ON</span> \</span><br><span class="line">-DWITH_JPEG=<span class="keyword">ON</span> \</span><br><span class="line">-DWITH_PNG=<span class="keyword">ON</span> \</span><br><span class="line">-DWITH_JASPER=<span class="keyword">ON</span> \</span><br><span class="line">-DWITH_TIFF=<span class="keyword">ON</span> \</span><br><span class="line">-DSOFTFP=<span class="keyword">ON</span> \</span><br><span class="line">-DBUILD_JAVA=<span class="keyword">OFF</span> \</span><br><span class="line">-DBUILD_ANDROID_EXAMPLES=<span class="keyword">OFF</span> \</span><br><span class="line">-DBUILD_ANDROID_PROJECTS=<span class="keyword">OFF</span> \</span><br><span class="line">-DANDROID_STL=c++_shared \</span><br><span class="line">-DANDROID_ABI=armeabi-v7a \</span><br><span class="line">-DBUILD_SHARED_LIBS=<span class="keyword">ON</span> \</span><br><span class="line">-DCMAKE_INSTALL_PREFIX=opencv/<span class="keyword">install</span> \</span><br><span class="line">..</span><br></pre></td></tr></table></figure></li>
<li><p>编译</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ make -j24 && make install</span><br></pre></td></tr></table></figure></li>
<li><p>检查生成文件</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> opencv/install/sdk</span><br><span class="line"><span class="comment"># etc 目录,存放了人脸识别模块部分资源文件,licenses等</span></span><br><span class="line">vectoros@vectoros:~/opencv/install/sdk$ ll etc/</span><br><span class="line">total 28</span><br><span class="line">drwxrwxr-x 5 vectoros vectoros 4096 Oct 8 10:50 ./</span><br><span class="line">drwxrwxr-x 4 vectoros vectoros 4096 Oct 8 10:50 ../</span><br><span class="line">drwxrwxr-x 2 vectoros vectoros 4096 Oct 8 10:50 haarcascades/</span><br><span class="line">drwxrwxr-x 2 vectoros vectoros 4096 Oct 8 10:50 lbpcascades/</span><br><span class="line">drwxrwxr-x 2 vectoros vectoros 4096 Oct 8 10:50 licenses/</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 2593 Aug 24 23:19 valgrind_3rdparty.supp</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 4088 Aug 24 23:19 valgrind.supp</span><br><span class="line"></span><br><span class="line"><span class="comment"># native/jni/include 目录,存放了对应的.h .hpp头文件</span></span><br><span class="line">vectoros@vectoros:~/opencv/install/sdk/native$ ll jni/include/</span><br><span class="line">drwxrwxr-x 16 vectoros vectoros 4096 Oct 8 10:50 opencv2/</span><br><span class="line"></span><br><span class="line"><span class="comment"># native/libs/armeabi-v7a/ 目录,存放了jni的so库或者.a文件</span></span><br><span class="line">vectoros@vectoros:~/opencv/install/sdk/native$ ll libs/armeabi-v7a/*.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 13462060 Oct 8 10:48 libs/armeabi-v7a/libopencv_calib3d.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 25141056 Oct 8 10:46 libs/armeabi-v7a/libopencv_core.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 50133564 Oct 8 10:47 libs/armeabi-v7a/libopencv_dnn.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 6983552 Oct 8 10:47 libs/armeabi-v7a/libopencv_features2d.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 3502996 Oct 8 10:46 libs/armeabi-v7a/libopencv_flann.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 525868 Oct 8 10:47 libs/armeabi-v7a/libopencv_highgui.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 21684136 Oct 8 10:47 libs/armeabi-v7a/libopencv_imgcodecs.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 26117996 Oct 8 10:46 libs/armeabi-v7a/libopencv_imgproc.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 6184124 Oct 8 10:46 libs/armeabi-v7a/libopencv_ml.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 3730776 Oct 8 10:49 libs/armeabi-v7a/libopencv_objdetect.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 5078460 Oct 8 10:47 libs/armeabi-v7a/libopencv_photo.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 7637264 Oct 8 10:49 libs/armeabi-v7a/libopencv_stitching.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 3361504 Oct 8 10:47 libs/armeabi-v7a/libopencv_videoio.so</span><br><span class="line">-rw-r--r-- 1 vectoros vectoros 3026088 Oct 8 10:49 libs/armeabi-v7a/libopencv_video.so</span><br></pre></td></tr></table></figure></li>
<li><p>讲生成的文件应用到AndroidStudio NDK Projects里面</p>
</li>
</ol>
<h2 id="编译配置解析"><a href="#编译配置解析" class="headerlink" title="编译配置解析"></a>编译配置解析</h2><figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line">-DCMAKE_TOOLCHAIN_FILE=/opt/ndk/build/cmake/android.toolchain.cmake <span class="comment"># 指定编译工具链cmake脚本</span></span><br><span class="line">-DANDROID_NDK=/opt/ndk <span class="comment"># 指定NDK路径</span></span><br><span class="line">-DANDROID_NATIVE_API_LEVEL=android-<span class="number">21</span> <span class="comment"># 指定NDK API Level</span></span><br><span class="line">-DCMAKE_BUILD_TYPE=Release <span class="comment"># 指定编译类型,默认是Debug类型,Release会有性能上的提升</span></span><br><span class="line">-DENABLE_VFPV3=<span class="keyword">ON</span> <span class="comment"># 开启VFP优化选项</span></span><br><span class="line">-DANDROID_ARM_NEON=<span class="keyword">TRUE</span> <span class="comment"># 设置NDK支持NEON</span></span><br><span class="line">-DENABLE_NEON=<span class="keyword">ON</span> <span class="comment"># 开启O彭CV NEON优化选项</span></span><br><span class="line">-DBUILD_PNG=<span class="keyword">ON</span> <span class="comment"># 编译PNG模块</span></span><br><span class="line">-DBUILD_JASPER=<span class="keyword">ON</span> <span class="comment"># 编译JASPER模块</span></span><br><span class="line">-DBUILD_JPEG=<span class="keyword">ON</span> <span class="comment"># 编译JPEG模块</span></span><br><span class="line">-DBUILD_TIFF=<span class="keyword">ON</span> <span class="comment"># 编译TIFF模块</span></span><br><span class="line">-DBUILD_ZLIB=<span class="keyword">ON</span> <span class="comment"># 编译ZLIB模块</span></span><br><span class="line">-DWITH_JPEG=<span class="keyword">ON</span> <span class="comment"># 生成JPEG模块</span></span><br><span class="line">-DWITH_PNG=<span class="keyword">ON</span> <span class="comment"># 生成PNG模块</span></span><br><span class="line">-DWITH_JASPER=<span class="keyword">ON</span> <span class="comment"># 生成JASPER模块</span></span><br><span class="line">-DWITH_TIFF=<span class="keyword">ON</span> <span class="comment"># 生成TIFF模块</span></span><br><span class="line">-DSOFTFP=<span class="keyword">ON</span> <span class="comment"># 开启SOFTFP</span></span><br><span class="line">-DBUILD_JAVA=<span class="keyword">OFF</span> <span class="comment"># 编译Java,这里只需要C++版本,如果需要java,设置为ON</span></span><br><span class="line">-DBUILD_ANDROID_EXAMPLES=<span class="keyword">OFF</span> <span class="comment"># 编译Android Examples</span></span><br><span class="line">-DBUILD_ANDROID_PROJECTS=<span class="keyword">OFF</span> <span class="comment"># 编译Android Projects</span></span><br><span class="line">-DANDROID_STL=c++_shared <span class="comment"># 指定STL版本,新版NDK里面默认使用c++_shared</span></span><br><span class="line">-DANDROID_ABI=armeabi-v7a <span class="comment"># 指定生成ABI版本</span></span><br><span class="line">-DBUILD_SHARED_LIBS=<span class="keyword">ON</span> <span class="comment"># 是否生成共享so库,如果不设置,默认生成.a静态库</span></span><br><span class="line">-DCMAKE_INSTALL_PREFIX=opencv/<span class="keyword">install</span> <span class="comment"># 安装路径,用于生成需要的头文件和so或者.a静态库(可选)</span></span><br><span class="line">.. <span class="comment"># 指定OpenCV代码根目录(重要)</span></span><br></pre></td></tr></table></figure>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ol>
<li><a href="https://www.learnopencv.com/install-opencv-on-android-tiny-and-optimized/">https://www.learnopencv.com/install-opencv-on-android-tiny-and-optimized/</a></li>
<li><a href="https://www.sisik.eu/blog/android/ndk/opencv-without-java">https://www.sisik.eu/blog/android/ndk/opencv-without-java</a></li>
</ol>
]]></content>
<categories>
<category>Android</category>
<category>NDK</category>
<category>OpenCV</category>
</categories>
<tags>
<tag>Android</tag>
<tag>NDK</tag>
<tag>OpenCV</tag>
<tag>CMake</tag>
</tags>
</entry>
<entry>
<title>Hexo tutorial</title>
<url>/post/1dbe5134.html</url>
<content><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>OR</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo s</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>OR</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo g</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>OR</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo d</span><br></pre></td></tr></table></figure>
<h3 id="Generate-Categories"><a href="#Generate-Categories" class="headerlink" title="Generate Categories"></a>Generate Categories</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new page categories</span><br></pre></td></tr></table></figure>
<p>Then open <code>source/categories/index.md</code>, Add <code>type: "categories"</code></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">---</span><br><span class="line">title: categories</span><br><span class="line">date: 2019-03-09 13:31:42</span><br><span class="line">type: "categories"</span><br><span class="line">comments: false</span><br><span class="line">---</span><br></pre></td></tr></table></figure>
<h3 id="Generate-Tags"><a href="#Generate-Tags" class="headerlink" title="Generate Tags"></a>Generate Tags</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new page tags</span><br></pre></td></tr></table></figure>
<p>Then open <code>source/tags/index.md</code>, Add <code>type: "tags"</code></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">---</span><br><span class="line">title: categories</span><br><span class="line">date: 2019-03-09 13:31:42</span><br><span class="line">type: "tags"</span><br><span class="line">comments: false</span><br><span class="line">---</span><br></pre></td></tr></table></figure>
<h3 id="Using-tags-or-categories"><a href="#Using-tags-or-categories" class="headerlink" title="Using tags or categories"></a>Using tags or categories</h3><p>Adding categories or tags description on page title</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">---</span><br><span class="line">title: Hexo tutorial</span><br><span class="line">tag: [Hexo,Tutorial]</span><br><span class="line">categories: </span><br><span class="line">- Web</span><br><span class="line">---</span><br></pre></td></tr></table></figure>
<h3 id="Clean-caches-and-regenerated"><a href="#Clean-caches-and-regenerated" class="headerlink" title="Clean caches and regenerated"></a>Clean caches and regenerated</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ hexo clean</span><br><span class="line">$ hexo g</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html">Deployment</a></p>
]]></content>
<categories>
<category>Web</category>
</categories>
<tags>
<tag>Tutorial</tag>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title>Create a Native Service on Android P</title>
<url>/post/67bab5c2.html</url>
<content><![CDATA[<p>在定制自己的Android嵌入式系统时候,有时我们需要创建一个Native Service用来和底层设备通信。</p>
<ul>
<li>Native Service其实是一个Linux守护进程,提供一些必要的服务。</li>
<li>Android提供了Binder进程间通信机制,Native Service就需要遵循Android的规则来实现</li>
</ul>
<h2 id="整体框架"><a href="#整体框架" class="headerlink" title="整体框架"></a>整体框架</h2><ul>
<li>Server (后台Service服务)</li>
<li>Client (提供和Service通信的接口)</li>
<li>JNI (持有一个Client端,封装对应的接口,用于和Service通信)</li>
<li>Java (JNI层提供给Java层的接口)</li>
<li>Selinux修改(Android 8以后)</li>
<li>预编译到系统中,供Framework调用(如何在framework.jar中调用我们自己生成的java接口)</li>
</ul>
<h2 id="代码实现框架"><a href="#代码实现框架" class="headerlink" title="代码实现框架"></a>代码实现框架</h2><p>代码我们以一个LED开关接口为例,添加一个NativeService,用来控制一个独立的LED灯的开关。</p>
<ul>
<li><p>创建组织代码目录</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># root directory</span></span><br><span class="line">mkdir LEDService</span><br><span class="line"><span class="built_in">cd</span> LEDService</span><br><span class="line"><span class="comment"># headers</span></span><br><span class="line">mkdir include</span><br><span class="line"><span class="comment"># hardware interface</span></span><br><span class="line">mkdir hal</span><br><span class="line"><span class="comment"># service implement</span></span><br><span class="line">mkdir service</span><br><span class="line"><span class="comment"># client test</span></span><br><span class="line">mkdir <span class="built_in">test</span></span><br><span class="line"><span class="comment"># JNI interface</span></span><br><span class="line">mkdir jni</span><br><span class="line"><span class="comment"># java interface</span></span><br><span class="line">mkdir java</span><br><span class="line"><span class="comment"># summary</span></span><br><span class="line">ls -l</span><br></pre></td></tr></table></figure>
<h2 id="编译脚本"><a href="#编译脚本" class="headerlink" title="编译脚本"></a>编译脚本</h2></li>
<li><p>为什么先写编译脚本?</p>
<ul>
<li>编译脚本可以预先帮助我们组织代码</li>
<li>我们可以提前知道需要编译输出什么</li>
</ul>
</li>
<li><p>我们需要生成哪几个文件</p>
<ul>
<li>libledservice.so 共享库,提供给Server端和Client端调用</li>
<li>libledservicemanager_jni.so JNI共享库,供Java接口调用</li>
<li>ledservicemanager.jar Jar包,提供给其他java层调用</li>
<li>ledservice.rc 服务启动的rc文件</li>
<li>com.vectoros.led.xml permission文件</li>
</ul>
</li>
<li><p>Android.mk</p>
<p>我们在LEDService目录下创建一个Android.mk用于编译C/C++ so, 可执行文件以及rc,xml等资源文件的编译输出。</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line"><span class="comment">################ LIB_LED_SERVICE ############</span></span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(CLEAR_VARS)</span></span><br><span class="line">LOCAL_MODULE:= libledservice</span><br><span class="line"></span><br><span class="line">LOCAL_SRC_FILES:= \</span><br><span class="line"> service/LEDService.cpp \</span><br><span class="line"> service/ILEDService.cpp \</span><br><span class="line"> service/LEDServiceManager.cpp</span><br><span class="line"></span><br><span class="line">LOCAL_C_INCLUDES += \</span><br><span class="line"> <span class="variable">$(LOCAL_PATH)</span>/<span class="keyword">include</span></span><br><span class="line"></span><br><span class="line">LOCAL_SHARED_LIBRARIES := \</span><br><span class="line"> libbinder \</span><br><span class="line"> libutils \</span><br><span class="line"> libcutils \</span><br><span class="line"> liblog</span><br><span class="line"></span><br><span class="line"><span class="comment"># Export include dir</span></span><br><span class="line">LOCAL_EXPORT_C_INCLUDE_DIRS := <span class="variable">$(LOCAL_PATH)</span>/<span class="keyword">include</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># LOCAL_CFLAGS += -mhard-float</span></span><br><span class="line"><span class="comment"># LOCAL_LDFLAGS += -Wl,--no-warn-mismatch</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(BUILD_SHARED_LIBRARY)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">################ LED_SERVICE ############</span></span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(CLEAR_VARS)</span></span><br><span class="line">LOCAL_MODULE:= ledservice</span><br><span class="line"></span><br><span class="line">LOCAL_SRC_FILES:= \</span><br><span class="line"> service/main_ledservice.cpp </span><br><span class="line"></span><br><span class="line">LOCAL_SHARED_LIBRARIES := \</span><br><span class="line"> libutils \</span><br><span class="line"> liblog \</span><br><span class="line"> libbinder \</span><br><span class="line"> libledservice</span><br><span class="line"></span><br><span class="line">LOCAL_MODULE_CLASS := EXECUTABLES</span><br><span class="line">LOCAL_INIT_RC := service/ledservice.rc</span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(BUILD_EXECUTABLE)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">################ LED_SERVICE_MANAGER_JNI ############</span></span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(CLEAR_VARS)</span></span><br><span class="line">LOCAL_MODULE:= libledservicemanager_jni</span><br><span class="line"></span><br><span class="line">LOCAL_SRC_FILES:= \</span><br><span class="line"> jni/com_vectoros_ledservice_manager_jni.cpp </span><br><span class="line"></span><br><span class="line">LOCAL_SHARED_LIBRARIES := \</span><br><span class="line"> libutils \</span><br><span class="line"> liblog \</span><br><span class="line"> libcutils \</span><br><span class="line"> libledservice \</span><br><span class="line"> libbinder</span><br><span class="line"></span><br><span class="line">LOCAL_CFLAGS += -Wno-unused-parameter</span><br><span class="line">LOCAL_LDFLAGS += -Wl,--no-warn-mismatch</span><br><span class="line"></span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(BUILD_SHARED_LIBRARY)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Using Android.bp to build java library</span></span><br><span class="line"><span class="comment"># ################# JAVA_LIBRARIES ############</span></span><br><span class="line"><span class="comment"># include $(CLEAR_VARS)</span></span><br><span class="line"><span class="comment"># LOCAL_MODULE:= ledservicemanager</span></span><br><span class="line"><span class="comment"># LOCAL_SRC_FILES:= \</span></span><br><span class="line"><span class="comment"># $(call all-java-files-under,java)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># LOCAL_MODULE_TAGS := optional</span></span><br><span class="line"><span class="comment"># LOCAL_NO_STANDARD_LIBRARIES := true</span></span><br><span class="line"><span class="comment"># LOCAL_DX_FLAGS := --core-library</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># include $(BUILD_JAVA_LIBRARY)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ################ PERMISION_FILES ############</span></span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(CLEAR_VARS)</span></span><br><span class="line">LOCAL_MODULE:= com.vectoros.led.xml</span><br><span class="line">LOCAL_MODULE_TAGS := optional</span><br><span class="line">LOCAL_MODULE_CLASS:= ETC</span><br><span class="line"></span><br><span class="line">LOCAL_SRC_FILES:= java/<span class="variable">$(LOCAL_MODULE)</span></span><br><span class="line">LOCAL_MODULE_PATH := <span class="variable">$(TARGET_OUT_ETC)</span>/permissions</span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(BUILD_PREBUILT)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">################ CMD_TEST_CLIENT ############</span></span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(CLEAR_VARS)</span></span><br><span class="line">LOCAL_MODULE:= ledserviceclient</span><br><span class="line"></span><br><span class="line">LOCAL_SRC_FILES:= \</span><br><span class="line"> test/main_ledservice_client.cpp</span><br><span class="line"></span><br><span class="line">LOCAL_SHARED_LIBRARIES := \</span><br><span class="line"> libbinder \</span><br><span class="line"> libutils \</span><br><span class="line"> libcutils \</span><br><span class="line"> liblog \</span><br><span class="line"> libledservice</span><br><span class="line"></span><br><span class="line">LOCAL_LDFLAGS += -Wl,--no-warn-mismatch</span><br><span class="line">LOCAL_MODULE_CLASS := EXECUTABLES</span><br><span class="line"><span class="keyword">include</span> <span class="variable">$(BUILD_EXECUTABLE)</span></span><br></pre></td></tr></table></figure></li>
<li><p>Andorid.bp</p>
<p>我们在java目录下,创建一个Android.bp文件,用于生成jar包。至于为什么必须要用Android.bp,会留在集成到framework里面的时候讲。</p>
<figure class="highlight"><table><tr><td class="code"><pre><span class="line">java_library {</span><br><span class="line"> name: "ledservicemanager",</span><br><span class="line"> srcs: [</span><br><span class="line"> "com/vectoros/led/*.java",</span><br><span class="line"> ],</span><br><span class="line"></span><br><span class="line"> hostdex: true,</span><br><span class="line"> java_version: "1.7",</span><br><span class="line"> no_framework_libs: true,</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
<li><p>总结</p>
<p>通过以上的编译脚本,我们知道了自己需要写哪些文件,会生成什么样的文件,接下来就可以往下写实现部分的代码了。</p>
</li>
</ul>
<h2 id="头文件实现"><a href="#头文件实现" class="headerlink" title="头文件实现"></a>头文件实现</h2><ul>
<li><p>主要有三个头文件</p>
<ul>
<li>LEDService.h</li>
<li>LEDServiceManager.h</li>
<li>ILEDService.h</li>
</ul>
</li>
<li><p>ILEDService.h</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> ANDROID_ILED_NATIVE_SERVICE_H</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> ANDROID_ILED_NATIVE_SERVICE_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdint.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/RefBase.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Singleton.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Errors.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/String16.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IInterface.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> android</span><br><span class="line">{</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">ILEDService</span> :</span> <span class="keyword">public</span> IInterface</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">DECLARE_META_INTERFACE</span>(LEDService);</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">int</span> <span class="title">initHardware</span><span class="params">(<span class="keyword">void</span>)</span> </span>= <span class="number">0</span>;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">releaseHardware</span><span class="params">(<span class="keyword">void</span>)</span> </span>= <span class="number">0</span>;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">on</span><span class="params">(<span class="keyword">void</span>)</span> </span>= <span class="number">0</span>;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">off</span><span class="params">(<span class="keyword">void</span>)</span> </span>= <span class="number">0</span>;</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">BnLEDService</span> :</span> <span class="keyword">public</span> BnInterface<ILEDService>{</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">status_t</span> <span class="title">onTransact</span><span class="params">(<span class="keyword">uint32_t</span> code, <span class="keyword">const</span> Parcel& data,</span></span></span><br><span class="line"><span class="function"><span class="params"> Parcel* reply, <span class="keyword">uint32_t</span> flags = <span class="number">0</span>)</span></span>;</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">enum</span> <span class="title">LED_SERVICE_TYPE</span>{</span></span><br><span class="line"> BASE_START,</span><br><span class="line"> ON,</span><br><span class="line"> OFF,</span><br><span class="line"> };</span><br><span class="line"> </span><br><span class="line">} <span class="comment">// namespace android</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">//ANDROID_ILED_NATIVE_SERVICE_H</span></span></span><br></pre></td></tr></table></figure></li>
<li><p>LEDService.h</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> ANDROID_LED_NATIVE_SERVICE_H</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> ANDROID_LED_NATIVE_SERVICE_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><map></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdint.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cutils/compiler.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Atomic.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Errors.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/KeyedVector.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/RefBase.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/SortedVector.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/threads.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/BinderService.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ILEDService.h"</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> android {</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">LEDService</span> :</span> <span class="keyword">public</span> BinderService<LEDService>, <span class="keyword">public</span> BnLEDService</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">char</span> <span class="keyword">const</span>* <span class="title">getServiceName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"LEDService"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">LEDService</span>();</span><br><span class="line"> ~<span class="built_in">LEDService</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">int</span> <span class="title">initHardware</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">releaseHardware</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">on</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">off</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> };</span><br><span class="line">}; <span class="comment">// namespace android</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">// ANDROID_LED_NATIVE_SERVICE_H</span></span></span><br></pre></td></tr></table></figure></li>
<li><p>LEDServiceManager.h</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> ANDROID_LED_NATIVE_MANAGER_H</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> ANDROID_LED_NATIVE_MANAGER_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdint.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IBinder.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/RefBase.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Singleton.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/threads.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ILEDService.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> android</span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">LEDServiceManager</span> :</span> <span class="keyword">public</span> Singleton<LEDServiceManager></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line"> <span class="comment">/* data */</span></span><br><span class="line"> <span class="keyword">bool</span> isDied;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">ledServiceDied</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">mutable</span> sp<ILEDService> mLEDService;</span><br><span class="line"> <span class="keyword">mutable</span> sp<IBinder::DeathRecipient> mDeathObserver;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">LEDServiceManager</span>(<span class="comment">/* args */</span>);</span><br><span class="line"> ~<span class="built_in">LEDServiceManager</span>();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">initHardware</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">releaseHardware</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">on</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">off</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">status_t</span> <span class="title">assertState</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">bool</span> <span class="title">checkService</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">resetServiceStatus</span><span class="params">()</span></span>;</span><br><span class="line"> };</span><br><span class="line">} <span class="comment">// namespace android</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">//ANDROID_LED_NATIVE_MANAGER_H</span></span></span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="客户端和服务端实现"><a href="#客户端和服务端实现" class="headerlink" title="客户端和服务端实现"></a>客户端和服务端实现</h2><ul>
<li>ILEDService.cpp<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdint.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><malloc.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/Parcel.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IMemory.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IPCThreadState.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IServiceManager.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ILEDService.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> __ANDROID__</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LOG_TAG <span class="meta-string">"ILEDService"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> ANDROID_API_LEVEL >= 26</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><log/log.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cutils/log.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> android</span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">enum</span>{</span></span><br><span class="line"> INIT_HARDWARE = IBinder::FIRST_CALL_TRANSACTION,</span><br><span class="line"> RELEASE_HARDWARE,</span><br><span class="line"> ON,</span><br><span class="line"> OFF,</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">BpLEDService</span> :</span> <span class="keyword">public</span> BpInterface<ILEDService></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">BpLEDService</span>(<span class="keyword">const</span> sp<IBinder>& impl) : BpInterface<ILEDService>(impl)</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"> <span class="function"><span class="keyword">int</span> <span class="title">initHardware</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> Parcel data, reply;</span><br><span class="line"> data.<span class="built_in">writeInterfaceToken</span>(ILEDService::<span class="built_in">getInterfaceDescriptor</span>());</span><br><span class="line"> <span class="built_in">remote</span>()-><span class="built_in">transact</span>(INIT_HARDWARE, data, &reply);</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">int</span>)reply.<span class="built_in">readInt32</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">releaseHardware</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> Parcel data, reply;</span><br><span class="line"> data.<span class="built_in">writeInterfaceToken</span>(ILEDService::<span class="built_in">getInterfaceDescriptor</span>());</span><br><span class="line"> <span class="built_in">remote</span>()-><span class="built_in">transact</span>(RELEASE_HARDWARE, data, &reply);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">on</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> Parcel data, reply;</span><br><span class="line"> data.<span class="built_in">writeInterfaceToken</span>(ILEDService::<span class="built_in">getInterfaceDescriptor</span>());</span><br><span class="line"> <span class="built_in">remote</span>()-><span class="built_in">transact</span>(ON, data, &reply);</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">int</span>) reply.<span class="built_in">readInt32</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">off</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> Parcel data, reply;</span><br><span class="line"> data.<span class="built_in">writeInterfaceToken</span>(ILEDService::<span class="built_in">getInterfaceDescriptor</span>());</span><br><span class="line"> <span class="built_in">remote</span>()-><span class="built_in">transact</span>(OFF, data, &reply);</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">int</span>) reply.<span class="built_in">readInt32</span>();</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="built_in">IMPLEMENT_META_INTERFACE</span>(LEDService, <span class="string">"android.vectoros.LEDService"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">status_t</span> <span class="title">BnLEDService::onTransact</span><span class="params">(<span class="keyword">uint32_t</span> code, <span class="keyword">const</span> Parcel& data, Parcel* reply, <span class="keyword">uint32_t</span> flags)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">char</span> *buff;</span><br><span class="line"> <span class="keyword">int</span> len, retval;</span><br><span class="line"> <span class="keyword">status_t</span> status;</span><br><span class="line"> </span><br><span class="line"> <span class="built_in"><span class="keyword">switch</span></span>(code) {</span><br><span class="line"> <span class="keyword">case</span> INIT_HARDWARE:{</span><br><span class="line"> <span class="built_in">CHECK_INTERFACE</span>(ILEDService, data, reply);</span><br><span class="line"> retval = <span class="built_in">initHardware</span>();</span><br><span class="line"> reply-><span class="built_in">writeInt32</span>(retval); </span><br><span class="line"> <span class="keyword">return</span> NO_ERROR;</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">case</span> RELEASE_HARDWARE:{</span><br><span class="line"> <span class="built_in">CHECK_INTERFACE</span>(ILEDService, data, reply); </span><br><span class="line"> <span class="built_in">releaseHardware</span>();</span><br><span class="line"> <span class="keyword">return</span> NO_ERROR;</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> ON:{</span><br><span class="line"> <span class="built_in">CHECK_INTERFACE</span>(ILEDService, data, reply);</span><br><span class="line"> <span class="built_in">on</span>();</span><br><span class="line"> <span class="keyword">return</span> NO_ERROR;</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">case</span> OFF:{</span><br><span class="line"> <span class="built_in">CHECK_INTERFACE</span>(ILEDService, data, reply);</span><br><span class="line"> <span class="built_in">off</span>();</span><br><span class="line"> <span class="keyword">return</span> NO_ERROR;</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="keyword">return</span> BBinder::<span class="built_in">onTransact</span>(code, data, reply, flags);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">} <span class="comment">// namespace android</span></span><br></pre></td></tr></table></figure></li>
<li>LEDService.cpp<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdint.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><math.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Errors.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/RefBase.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Singleton.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/String16.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/BinderService.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IServiceManager.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"LEDService.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUFFER_SIZE 512</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> __ANDROID__</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LOG_TAG <span class="meta-string">"LEDService"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> ANDROID_API_LEVEL >= 26</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><log/log.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cutils/log.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> android {</span><br><span class="line"></span><br><span class="line">LEDService::<span class="built_in">LEDService</span>()</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">ALOGI</span>(<span class="string">"LEDService()"</span>); </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">LEDService::~<span class="built_in">LEDService</span>(){</span><br><span class="line"> <span class="built_in">ALOGI</span>(<span class="string">"~LEDService()"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">LEDService::initHardware</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">ALOGI</span>(<span class="string">"initHardware(), check camera env."</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">LEDService::releaseHardware</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">ALOGI</span>(<span class="string">"releaseHardware()"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">LEDService::on</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">ALOGI</span>(<span class="string">"on()"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">LEDService::off</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">ALOGI</span>(<span class="string">"off()"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}; <span class="comment">// namespace android</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
<li>LEDServiceManager.cpp<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdint.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Errors.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/RefBase.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utils/Singleton.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> __ANDROID__</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LOG_TAG <span class="meta-string">"LEDServiceManager"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> ANDROID_API_LEVEL >= 26</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><log/log.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cutils/log.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IBinder.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IServiceManager.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ILEDService.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"LEDServiceManager.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> android</span><br><span class="line">{</span><br><span class="line"> LEDServiceManager::<span class="built_in">LEDServiceManager</span>() : <span class="built_in">isDied</span>(<span class="literal">false</span>)</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"> LEDServiceManager::~<span class="built_in">LEDServiceManager</span>()</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"> <span class="function"><span class="keyword">void</span> <span class="title">LEDServiceManager::LEDServiceDied</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> isDied = <span class="literal">true</span>;</span><br><span class="line"> mLEDService.<span class="built_in">clear</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">status_t</span> <span class="title">LEDServiceManager::assertState</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (mLEDService == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="comment">// try for one second</span></span><br><span class="line"> <span class="function"><span class="keyword">const</span> String16 <span class="title">name</span><span class="params">(<span class="string">"LEDService"</span>)</span></span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">0</span> ; i<<span class="number">4</span> ; i++) {</span><br><span class="line"> <span class="keyword">status_t</span> err = <span class="built_in">getService</span>(name, &mLEDService);</span><br><span class="line"> <span class="keyword">if</span> (err == NAME_NOT_FOUND) {</span><br><span class="line"> <span class="built_in">usleep</span>(<span class="number">250000</span>);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (err != NO_ERROR) {</span><br><span class="line"> <span class="built_in">ALOGE</span>(<span class="string">"LEDService not found"</span>);</span><br><span class="line"> <span class="keyword">return</span> err;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">initLEDServiceNative</span>();</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">DeathObserver</span> :</span> <span class="keyword">public</span> IBinder::DeathRecipient {</span><br><span class="line"> LEDServiceManager& mLEDServiceManager;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">binderDied</span><span class="params">(<span class="keyword">const</span> wp<IBinder>& who)</span> </span>{</span><br><span class="line"> <span class="built_in">ALOGW</span>(<span class="string">"LEDService died [%p]"</span>, who.<span class="built_in">unsafe_get</span>());</span><br><span class="line"> mLEDServiceManager.<span class="built_in">LEDServiceDied</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">DeathObserver</span>(LEDServiceManager& mgr) : <span class="built_in">mLEDServiceManager</span>(mgr) { }</span><br><span class="line"> };</span><br><span class="line"> </span><br><span class="line"> mDeathObserver = <span class="keyword">new</span> <span class="built_in">DeathObserver</span>(*<span class="keyword">const_cast</span><LEDServiceManager *>(<span class="keyword">this</span>));</span><br><span class="line"> mLEDService-><span class="built_in">asBinder</span>(mLEDService)-><span class="built_in">linkToDeath</span>(mDeathObserver);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> NO_ERROR;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">bool</span> <span class="title">LEDServiceManager::checkService</span><span class="params">()</span> <span class="keyword">const</span> </span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> isDied? <span class="literal">true</span>:<span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">LEDServiceManager::resetServiceStatus</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> isDied = <span class="literal">false</span>; </span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">LEDServiceManager::initHardware</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> mLEDService-><span class="built_in">initHardware</span>(); </span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">LEDServiceManager::releaseHardware</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> mLEDService-><span class="built_in">releaseHardware</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">LEDServiceManager::on</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> mLEDService-><span class="built_in">on</span>();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">LEDServiceManager::off</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> mLEDService-><span class="built_in">off</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">} <span class="comment">// namespace android</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
<li>main_LED_service.cpp<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/BinderService.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><LEDService.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IPCThreadState.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/ProcessState.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><binder/IServiceManager.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ILEDService.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> android;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span>** argv)</span> </span>{</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 1</span></span><br><span class="line"> LEDService::<span class="built_in">publishAndJoinThreadPool</span>(<span class="literal">true</span>);</span><br><span class="line"> <span class="comment">// Like the SurfaceFlinger, limit the number of binder threads to 4.</span></span><br><span class="line"> ProcessState::<span class="built_in">self</span>()-><span class="built_in">setThreadPoolMaxThreadCount</span>(<span class="number">4</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> </span><br><span class="line"> <span class="function">sp<ProcessState> <span class="title">proc</span><span class="params">(ProcessState::self())</span></span>;</span><br><span class="line"></span><br><span class="line"> sp<IServiceManager> sm = <span class="built_in">defaultServiceManager</span>();</span><br><span class="line"></span><br><span class="line"> sm-><span class="built_in">addService</span>(<span class="built_in">String16</span>(<span class="string">"LEDService"</span>), <span class="keyword">new</span> <span class="built_in">LEDService</span>());</span><br><span class="line"></span><br><span class="line"> ProcessState::<span class="built_in">self</span>()-><span class="built_in">startThreadPool</span>();</span><br><span class="line"> ProcessState::<span class="built_in">self</span>()-><span class="built_in">giveThreadPoolName</span>();</span><br><span class="line"> IPCThreadState::<span class="built_in">self</span>()-><span class="built_in">joinThreadPool</span>();</span><br><span class="line"> ProcessState::<span class="built_in">self</span>()-><span class="built_in">setThreadPoolMaxThreadCount</span>(<span class="number">4</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="客户端服务端测试程序"><a href="#客户端服务端测试程序" class="headerlink" title="客户端服务端测试程序"></a>客户端服务端测试程序</h2><h2 id="JNI接口"><a href="#JNI接口" class="headerlink" title="JNI接口"></a>JNI接口</h2><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">#include <jni.h></span><br><span class="line">#include <cstdio></span><br><span class="line">#include <map></span><br><span class="line">#include <stdlib.h></span><br><span class="line">#include <string.h></span><br><span class="line"></span><br><span class="line">#include "LEDServiceManager.h"</span><br><span class="line"></span><br><span class="line">#ifdef __ANDROID__</span><br><span class="line">#define LOG_TAG "LEDServiceManagerJNI"</span><br><span class="line">#if ANDROID_API_LEVEL >= 26</span><br><span class="line">#include <log/log.h></span><br><span class="line">#else</span><br><span class="line">#include <cutils/log.h></span><br><span class="line">#endif</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line">#define JNIREG_CLASS "com/vectoros/led/LEDServiceManager"</span><br><span class="line"></span><br><span class="line">namespace android</span><br><span class="line">{</span><br><span class="line">static jint nativeOn(JNIEnv *env, jclass jcls)</span><br><span class="line">{</span><br><span class="line"> int err;</span><br><span class="line"> if (ledmgr)</span><br><span class="line"> {</span><br><span class="line"> err = ledmgr->assertState();</span><br><span class="line"> if (err == NO_ERROR)</span><br><span class="line"> {</span><br><span class="line"> return ledmgr->on();</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> return err;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> ALOGE("ledmgr is not init!\n");</span><br><span class="line"> return NO_INIT;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">static jint nativeOff(JNIEnv *env, jclass jcls)</span><br><span class="line">{</span><br><span class="line"> int err;</span><br><span class="line"> if (ledmgr)</span><br><span class="line"> {</span><br><span class="line"> err = ledmgr->assertState();</span><br><span class="line"> if (err == NO_ERROR)</span><br><span class="line"> {</span><br><span class="line"> return ledmgr->off();</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> return err;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> ALOGE("ledmgr is not init!\n");</span><br><span class="line"> return NO_INIT;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">static JNINativeMethod nativeMethods[] = {</span><br><span class="line"> {"nativeOn", "()I", (jint *)nativeOn},</span><br><span class="line"> {"nativeOff", "()I", (jint *)nativeOff},</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">int register_vectoros_LEDService(JNIEnv *env)</span><br><span class="line">{</span><br><span class="line"> jclass clazz = env->FindClass(JNIREG_CLASS);</span><br><span class="line"> if (clazz == NULL)</span><br><span class="line"> {</span><br><span class="line"> ALOGE("Native registeration unable to find class '%s'", JNIREG_CLASS);</span><br><span class="line"> return JNI_FALSE;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (env->RegisterNatives(clazz, nativeMethods, sizeof(nativeMethods) / sizeof(nativeMethods[0])) < 0)</span><br><span class="line"> {</span><br><span class="line"> env->DeleteLocalRef(clazz);</span><br><span class="line"> ALOGE("RegisterNatives failed for '%s'", JNIREG_CLASS);</span><br><span class="line"> return JNI_FALSE;</span><br><span class="line"> }</span><br><span class="line"> return JNI_TRUE;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">} // namespace android</span><br><span class="line"></span><br><span class="line">using namespace android;</span><br><span class="line"></span><br><span class="line">extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)</span><br><span class="line">{</span><br><span class="line"> JNIEnv *env = NULL;</span><br><span class="line"> if (vm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK)</span><br><span class="line"> {</span><br><span class="line"> return JNI_ERR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ALOG_ASSERT(env, "Could not retrieve the env!");</span><br><span class="line"></span><br><span class="line"> if (JNI_TRUE != register_vectoros_LEDService(env))</span><br><span class="line"> {</span><br><span class="line"> return JNI_ERR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return JNI_VERSION_1_6;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="Java接口"><a href="#Java接口" class="headerlink" title="Java接口"></a>Java接口</h2><ul>
<li>LEDServiceManager.java<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> com.vectoros.led;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LEDServiceManager</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">"LEDServiceManager"</span>;</span><br><span class="line"> <span class="keyword">static</span>{</span><br><span class="line"> System.loadLibrary(<span class="string">"LEDServiceManager_jni"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">on</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> nativeOn();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">off</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> nativeOff();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">int</span> <span class="title">nativeOn</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">int</span> <span class="title">nativeOff</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
]]></content>
<categories>
<category>Android</category>
<category>NDK</category>
<category>Service</category>
</categories>
<tags>
<tag>Android</tag>
<tag>NDK</tag>
<tag>Service</tag>
</tags>
</entry>
<entry>
<title>Numpy 函数中axis的含义</title>
<url>/post/31a06e56.html</url>
<content><![CDATA[<p>Numpy中很多的基本操作函数,都有一个参数<code>axis</code>,比如:</p>
<ol>
<li>argmax 返回最大元素的索引</li>
<li>argmin 返回最大元素的索引</li>
<li>sum</li>
<li>max</li>
<li>min</li>
<li>mean</li>
<li>average</li>
<li>median</li>
</ol>
<h3 id="官方解释"><a href="#官方解释" class="headerlink" title="官方解释"></a>官方解释</h3><p>我们从<code>numpy doc</code>里面的<code>argmax</code>函数可以看到下面的解释(有删减)</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">argmax</span>(<span class="params">a, axis=<span class="literal">None</span>, out=<span class="literal">None</span></span>):</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> Returns the indices of the maximum values along an axis.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> Parameters</span></span><br><span class="line"><span class="string"> ----------</span></span><br><span class="line"><span class="string"> a : array_like</span></span><br><span class="line"><span class="string"> Input array. # Numpy数组</span></span><br><span class="line"><span class="string"> axis : int, optional # 整数(可正可负),可选</span></span><br><span class="line"><span class="string"> By default, the index is into the flattened array, otherwise</span></span><br><span class="line"><span class="string"> along the specified axis.</span></span><br><span class="line"><span class="string"> # 默认是一个扁平数组,否则根据指定的axis</span></span><br><span class="line"><span class="string"> Returns</span></span><br><span class="line"><span class="string"> -------</span></span><br><span class="line"><span class="string"> index_array : ndarray of ints</span></span><br><span class="line"><span class="string"> Array of indices into the array. It has the same shape as `a.shape`</span></span><br><span class="line"><span class="string"> with the dimension along `axis` removed.</span></span><br><span class="line"><span class="string"> # 返回数组的一个切片,和a的shape相同,但是移除了axis这个维度。</span></span><br></pre></td></tr></table></figure>
<h3 id="官方-Examples"><a href="#官方-Examples" class="headerlink" title="官方 Examples"></a>官方 <code>Examples</code></h3><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span>a = np.arange(<span class="number">6</span>).reshape(<span class="number">2</span>,<span class="number">3</span>)</span><br><span class="line"><span class="meta">>>> </span>a</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>],</span><br><span class="line"> [<span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]])</span><br><span class="line"><span class="meta">>>> </span>np.argmax(a) <span class="comment"># 未指定axis,模式整个数组是一个扁平数组,取所有元素的最大值的下标</span></span><br><span class="line"><span class="number">5</span></span><br><span class="line"><span class="meta">>>> </span>np.argmax(a, axis=<span class="number">0</span>) <span class="comment"># a.shape=(2,3), 当axis=0时,输出的shape是(3)</span></span><br><span class="line">array([<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>])</span><br><span class="line"><span class="meta">>>> </span>np.argmax(a, axis=<span class="number">1</span>) <span class="comment"># 当axis=1时,输出的shape是(2)</span></span><br><span class="line">array([<span class="number">2</span>, <span class="number">2</span>])</span><br><span class="line"></span><br><span class="line">Indexes of the maximal elements of a N-dimensional array:</span><br><span class="line"><span class="comment"># 不展开index, 保留原始结构</span></span><br><span class="line"><span class="meta">>>> </span>ind = np.unravel_index(np.argmax(a, axis=<span class="literal">None</span>), a.shape)</span><br><span class="line"><span class="meta">>>> </span>ind</span><br><span class="line">(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line"><span class="meta">>>> </span>a[ind]</span><br><span class="line"><span class="number">5</span></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>b = np.arange(<span class="number">6</span>)</span><br><span class="line"><span class="meta">>>> </span>b[<span class="number">1</span>] = <span class="number">5</span></span><br><span class="line"><span class="meta">>>> </span>b</span><br><span class="line">array([<span class="number">0</span>, <span class="number">5</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line"><span class="meta">>>> </span>np.argmax(b) <span class="comment"># Only the first occurrence is returned. # 只输出第一个出现的最大值下标</span></span><br><span class="line"><span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="string">"""</span></span><br></pre></td></tr></table></figure>
<h3 id="怎么样更好的理解axis呢?"><a href="#怎么样更好的理解axis呢?" class="headerlink" title="怎么样更好的理解axis呢?"></a>怎么样更好的理解<code>axis</code>呢?</h3><p>以<code>argmax</code>为例,功能是返回最大元素的索引。可以这么来理解。</p>
<ul>
<li><p>当数组是一维的,里面的元素就是一维数组里面的单个值,此时<code>axis</code>是没有作用的,只能取值为 <code>0</code>,比如</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="meta">>>> </span>a = np.array([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>])</span><br><span class="line"><span class="meta">>>> </span>np.argmax(a)</span><br><span class="line"><span class="number">6</span></span><br></pre></td></tr></table></figure></li>
<li><p>当数组是二维的,就分了几种情况:</p>
<ul>
<li>不指定axis时,把整个数组当作一维数组来处理,假定数组是3x3,二维数组 <figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span>arr = np.array([[<span class="number">1</span>, <span class="number">3</span>, <span class="number">5</span>],[<span class="number">2</span>, <span class="number">4</span>, <span class="number">6</span>],[<span class="number">3</span>, <span class="number">5</span>, <span class="number">8</span>]])</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr.shape)</span><br><span class="line">(<span class="number">3</span>, <span class="number">3</span>)</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr)</span><br><span class="line">[[<span class="number">1</span> <span class="number">3</span> <span class="number">5</span>]</span><br><span class="line"> [<span class="number">2</span> <span class="number">4</span> <span class="number">6</span>]</span><br><span class="line"> [<span class="number">3</span> <span class="number">5</span> <span class="number">8</span>]]</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr) <span class="comment"># 不指定axis时,把整个数组展开成一维数组来处理</span></span><br><span class="line"><span class="number">8</span></span><br></pre></td></tr></table></figure></li>
<li>当<code>axis=0</code>时,假定数组是2x3,二维数组,输出的shape应该是有3个元素的索引的一维数组,按列统计,共有3列,给出每列最大值在列方向上的索引 <figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span>arr = np.array([[<span class="number">1</span>, <span class="number">3</span>, <span class="number">5</span>],[<span class="number">6</span>, <span class="number">4</span>, <span class="number">2</span>]])</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr)</span><br><span class="line">[[<span class="number">1</span> <span class="number">3</span> <span class="number">5</span>]</span><br><span class="line"> [<span class="number">6</span> <span class="number">4</span> <span class="number">2</span>]]</span><br><span class="line"><span class="comment"># 第一列最大值时6,在列方向上的索引为1</span></span><br><span class="line"><span class="comment"># 第二列最大值为4,在列方向上的索引为1 </span></span><br><span class="line"><span class="comment"># 第二列最大值为5,在列方向上的索引为0</span></span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">0</span>) </span><br><span class="line">array([<span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=-<span class="number">2</span>)</span><br><span class="line">array([<span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>], dtype=int64)</span><br></pre></td></tr></table></figure></li>
<li>当<code>axis=1</code>时,假定数组是2x3,二维数组,输出的shape应该是有2个元素的索引的一维数组,按行统计,共有3行,给出每行最大值在行方向上的索引 <figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span>arr = np.array([[<span class="number">1</span>, <span class="number">3</span>, <span class="number">5</span>],[<span class="number">6</span>, <span class="number">4</span>, <span class="number">2</span>]])</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr)</span><br><span class="line">[[<span class="number">1</span> <span class="number">3</span> <span class="number">5</span>]</span><br><span class="line"> [<span class="number">6</span> <span class="number">4</span> <span class="number">2</span>]]</span><br><span class="line"><span class="comment"># 第一行最大值时5,在行方向上的索引为2</span></span><br><span class="line"><span class="comment"># 第二行最大值为6,在行方向上的索引为0 </span></span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">1</span>)</span><br><span class="line">array([<span class="number">2</span>, <span class="number">0</span>], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=-<span class="number">1</span>)</span><br><span class="line">array([<span class="number">2</span>, <span class="number">0</span>], dtype=int64)</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>当数组是三维数组时。</p>
<ul>
<li>不指定<code>axis</code>时,将数组展开成一维数组,很好理解</li>
<li>当<code>axis=0</code>时,假定数组时2x3x2的三维数组,输出的shape应该是3x2个元素的索引的二维数组。 <figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span>arr = np.random.randint(<span class="number">12</span>, size=(<span class="number">2</span>, <span class="number">3</span>, <span class="number">2</span>))</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr)</span><br><span class="line">[[[<span class="number">11</span> <span class="number">8</span>]</span><br><span class="line"> [<span class="number">11</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">7</span> <span class="number">0</span>]]</span><br><span class="line"></span><br><span class="line"> [[ <span class="number">8</span> <span class="number">10</span>]</span><br><span class="line"> [ <span class="number">9</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">4</span> <span class="number">10</span>]]]</span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr[<span class="number">0</span>,:,:])</span><br><span class="line">[[<span class="number">11</span> <span class="number">8</span>]</span><br><span class="line"> [<span class="number">11</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">7</span> <span class="number">0</span>]]</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr[<span class="number">1</span>,:,:])</span><br><span class="line">[[ <span class="number">8</span> <span class="number">10</span>]</span><br><span class="line"> [ <span class="number">9</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">4</span> <span class="number">10</span>]]</span><br><span class="line"><span class="comment"># 分别对比 arr[0,:,:], arr[1,:,:] 对应位置,取其中最大值的索引,索引取值范围[0-1]</span></span><br><span class="line"><span class="comment"># out[0][0] = index(max(11, 8)) = 0</span></span><br><span class="line"><span class="comment"># out[0][1] = index(max(8, 10)) = 1</span></span><br><span class="line"><span class="comment"># out[1][0] = index(max(11, 9)) = 0</span></span><br><span class="line"><span class="comment"># out[1][1] = index(max(5, 5)) = 0</span></span><br><span class="line"><span class="comment"># out[2][0] = index(max(7, 4)) = 0</span></span><br><span class="line"><span class="comment"># out[2][1] = index(max(0, 10)) = 1 </span></span><br><span class="line"><span class="comment"># out = [[0, 1],</span></span><br><span class="line"><span class="comment"># [0, 0],</span></span><br><span class="line"><span class="comment"># [0, 1]]</span></span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(np.argmax(arr, axis=<span class="number">0</span>).shape)</span><br><span class="line">(<span class="number">3</span>, <span class="number">2</span>) </span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">0</span>)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">1</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">1</span>]], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=-<span class="number">3</span>)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">1</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">1</span>]], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">0</span>-arr.ndim)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">1</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">1</span>]], dtype=int64)</span><br></pre></td></tr></table></figure></li>
<li>当<code>axis=1</code>时,假定数组时2x3x2的三维数组,输出的shape应该是2x2个元素的索引的二维数组。 <figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span>arr = np.random.randint(<span class="number">12</span>, size=(<span class="number">2</span>, <span class="number">3</span>, <span class="number">2</span>))</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr)</span><br><span class="line">[[[<span class="number">11</span> <span class="number">8</span>]</span><br><span class="line"> [<span class="number">11</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">7</span> <span class="number">0</span>]]</span><br><span class="line"></span><br><span class="line"> [[ <span class="number">8</span> <span class="number">10</span>]</span><br><span class="line"> [ <span class="number">9</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">4</span> <span class="number">10</span>]]]</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr[:,<span class="number">0</span>,:])</span><br><span class="line">[[<span class="number">11</span> <span class="number">8</span>]</span><br><span class="line"> [ <span class="number">8</span> <span class="number">10</span>]]</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr[:,<span class="number">1</span>,:])</span><br><span class="line">[[<span class="number">11</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">9</span> <span class="number">5</span>]]</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr[:,<span class="number">2</span>,:])</span><br><span class="line">[[ <span class="number">7</span> <span class="number">0</span>]</span><br><span class="line"> [ <span class="number">4</span> <span class="number">10</span>]]</span><br><span class="line"><span class="comment"># 分别对比 arr[:,0,:], arr[:,1,:], arr[:,2,:] 对应位置,取其中最大值的索引,索引取值范围[0-2] </span></span><br><span class="line"><span class="comment"># out[0][0] = index(max(11, 11, 7 )) = 0</span></span><br><span class="line"><span class="comment"># out[0][1] = index(max(8 , 5, 0 )) = 0</span></span><br><span class="line"><span class="comment"># out[1][0] = index(max(8 , 9, 4 )) = 1</span></span><br><span class="line"><span class="comment"># out[1][1] = index(max(10, 5, 10)) = 0</span></span><br><span class="line"><span class="comment"># out = [[0, 0],</span></span><br><span class="line"><span class="comment"># [1, 0]]</span></span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(np.argmax(arr, axis=<span class="number">1</span>).shape)</span><br><span class="line">(<span class="number">2</span>, <span class="number">2</span>)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">1</span>)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">1</span>, <span class="number">0</span>]], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=-<span class="number">2</span>)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">1</span>, <span class="number">0</span>]], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">1</span>-arr.ndim)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">1</span>, <span class="number">0</span>]], dtype=int64)</span><br></pre></td></tr></table></figure></li>
<li>当<code>axis=2</code>时,假定数组时2x3x2的三维数组,输出的shape应该是2x3个元素的索引的二维数组。我们将数组的三个维度依次称为行,列,高 <figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="meta">>>> </span>arr = np.random.randint(<span class="number">12</span>, size=(<span class="number">2</span>, <span class="number">3</span>, <span class="number">2</span>))</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr)</span><br><span class="line">[[[<span class="number">11</span> <span class="number">8</span>]</span><br><span class="line"> [<span class="number">11</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">7</span> <span class="number">0</span>]]</span><br><span class="line"></span><br><span class="line"> [[ <span class="number">8</span> <span class="number">10</span>]</span><br><span class="line"> [ <span class="number">9</span> <span class="number">5</span>]</span><br><span class="line"> [ <span class="number">4</span> <span class="number">10</span>]]]</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr[:,:,<span class="number">0</span>])</span><br><span class="line">[[<span class="number">11</span> <span class="number">11</span> <span class="number">7</span>]</span><br><span class="line"> [ <span class="number">8</span> <span class="number">9</span> <span class="number">4</span>]]</span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(arr[:,:,<span class="number">1</span>])</span><br><span class="line">[[ <span class="number">8</span> <span class="number">5</span> <span class="number">0</span>]</span><br><span class="line"> [<span class="number">10</span> <span class="number">5</span> <span class="number">10</span>]] </span><br><span class="line"><span class="meta">>>> </span><span class="built_in">print</span>(np.argmax(arr, axis=<span class="number">2</span>).shape)</span><br><span class="line">(<span class="number">2</span>, <span class="number">3</span>) </span><br><span class="line"><span class="comment"># 分别对比 arr[:,:,0], arr[:,:,1] 对应位置,取其中最大值的索引,索引取值范围[0-1]</span></span><br><span class="line"><span class="comment"># out[0][0] = index(max(11, 8)) = 0</span></span><br><span class="line"><span class="comment"># out[0][1] = index(max(11, 5)) = 0</span></span><br><span class="line"><span class="comment"># out[0][2] = index(max(7 , 0)) = 0</span></span><br><span class="line"><span class="comment"># out[1][0] = index(max(8 , 10)) = 1</span></span><br><span class="line"><span class="comment"># out[1][1] = index(max(9 , 5)) = 0</span></span><br><span class="line"><span class="comment"># out[1][2] = index(max(4 , 10)) = 1 </span></span><br><span class="line"><span class="comment"># out = [[0, 0, 0],</span></span><br><span class="line"><span class="comment"># [1, 0, 1]]</span></span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">2</span>)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>]], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=-<span class="number">1</span>)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>]], dtype=int64)</span><br><span class="line"><span class="meta">>>> </span>np.argmax(arr, axis=<span class="number">2</span>-arr.ndim)</span><br><span class="line">array([[<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>],</span><br><span class="line"> [<span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>]], dtype=int64)</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
]]></content>
<categories>
<category>Python</category>
<category>Numpy</category>
</categories>
<tags>
<tag>Python</tag>
<tag>Numpy</tag>
</tags>
</entry>
<entry>
<title>NDK JNI中动态注册和静态注册,native和static native区别</title>
<url>/post/17976623.html</url>
<content><![CDATA[<p>动态注册和静态注册在JNI开发中是必然会遇到的问题。在最新的AndroidStudio中,默认使用的是静态注册,但是动态注册确实一种更加灵活的方式。</p>
<h2 id="静态注册"><a href="#静态注册" class="headerlink" title="静态注册"></a>静态注册</h2><p>在AndroidStudio中,创建项目时选择Native C++项目,会帮我们默认创建以下几个文件。</p>
<ul>
<li><p>MainActivity.java Java文件,包含JNI Java层接口</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>{</span><br><span class="line"></span><br><span class="line"><span class="comment">// Used to load the 'native-lib' library on application startup.</span></span><br><span class="line"><span class="keyword">static</span> {</span><br><span class="line"> System.loadLibrary(<span class="string">"native-lib"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_main);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Example of a call to a native method</span></span><br><span class="line"> TextView tv = findViewById(R.id.sample_text);</span><br><span class="line"> tv.setText(stringFromJNI());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A native method that is implemented by the 'native-lib' native library,</span></span><br><span class="line"><span class="comment"> * which is packaged with this application.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">native</span> String <span class="title">stringFromJNI</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
<li><p>native-lib.cpp C++文件,包含JNI函数的实现</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><jni.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> JNIEXPORT jstring JNICALL</span><br><span class="line"><span class="built_in">Java_com_vectoros_jnimethod_MainActivity_stringFromJNI</span>(</span><br><span class="line"> JNIEnv *env,</span><br><span class="line"> jobject <span class="comment">/* this */</span>) {</span><br><span class="line"> std::string hello = <span class="string">"Hello from C++"</span>;</span><br><span class="line"> <span class="keyword">return</span> env-><span class="built_in">NewStringUTF</span>(hello.<span class="built_in">c_str</span>());</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
<li><p>CMakeLists.txt CMake编译脚本</p>
<figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">cmake_minimum_required(VERSION 3.4.1)</span><br><span class="line"></span><br><span class="line">add_library( <span class="comment"># Sets the name of the library.</span></span><br><span class="line"> native-lib</span><br><span class="line"> SHARED</span><br><span class="line"> native-lib.cpp)</span><br><span class="line"></span><br><span class="line">find_library( <span class="comment"># Sets the name of the path variable.</span></span><br><span class="line"> log-lib</span><br><span class="line"> log)</span><br><span class="line"></span><br><span class="line">target_link_libraries( <span class="comment"># Specifies the target library.</span></span><br><span class="line"> native-lib</span><br><span class="line"> ${log-lib})</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="动态注册"><a href="#动态注册" class="headerlink" title="动态注册"></a>动态注册</h2><p>动态注册需要写的代码会多一些,我们可以参考Framework的很多JNI接口的实现。Java层的代码不需要变化,CMake也不需要修改(如果有引入其他头文件,需要在CMake里面增加对应的库)</p>
<ul>
<li><p>JNINativeMethod<br>动态注册过程中,需要使用结构体JNINativeMethod来记录java方法和jni函数的对应关系</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span>* name; <span class="comment">//Java方法名</span></span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span>* signature; <span class="comment">//方法的参数和返回值,使用字符串记录,格式形如`()V, (I)I`,括号内表示函数参数,括号右侧表示函数返回值</span></span><br><span class="line"> <span class="keyword">void</span>* fnPtr; <span class="comment">// 指向JNI函数的函数指针</span></span><br><span class="line">} JNINativeMethod;</span><br></pre></td></tr></table></figure></li>
<li><p>数据类型映射</p>
<ul>
<li><p>基本数据类型</p>
<table>
<thead>
<tr>
<th>Java类型</th>
<th>Native类型</th>
<th>域描述符</th>
<th>补充</th>
</tr>
</thead>
<tbody><tr>
<td>boolean</td>
<td>jboolean</td>
<td>Z</td>
<td></td>
</tr>
<tr>
<td>byte</td>
<td>jbyte</td>
<td>B</td>
<td></td>
</tr>
<tr>
<td>char</td>
<td>jchar</td>
<td>C</td>
<td></td>
</tr>
<tr>
<td>short</td>
<td>jshort</td>
<td>S</td>
<td></td>
</tr>
<tr>
<td>int</td>
<td>jint</td>
<td>I</td>
<td></td>
</tr>
<tr>
<td>long</td>
<td>jlong</td>
<td>J</td>
<td></td>
</tr>
<tr>
<td>float</td>
<td>jfloat</td>
<td>F</td>
<td></td>
</tr>
<tr>
<td>double</td>
<td>jdouble</td>
<td>D</td>
<td></td>
</tr>
<tr>
<td>void</td>
<td>void</td>
<td>V</td>
<td></td>
</tr>
</tbody></table>
</li>
<li><p>数组引用类型</p>
<table>
<thead>
<tr>
<th>Java类型</th>
<th>Native类型</th>
<th>域描述符</th>
<th>补充</th>
</tr>
</thead>
<tbody><tr>
<td>boolean[]</td>
<td>jbooleanArray</td>
<td>[Z</td>
<td></td>
</tr>
<tr>
<td>byte[]</td>
<td>jbyteArray</td>
<td>[B</td>
<td></td>
</tr>
<tr>
<td>char[]</td>
<td>jcharArray</td>
<td>[C</td>
<td></td>
</tr>
<tr>
<td>short[]</td>
<td>jshortArray</td>
<td>[S</td>
<td></td>
</tr>
<tr>
<td>int[]</td>
<td>jintArray</td>
<td>[I</td>
<td></td>
</tr>
<tr>
<td>long[]</td>
<td>jlongArray</td>
<td>[J</td>
<td></td>
</tr>
<tr>
<td>float[]</td>
<td>jfloatArray</td>
<td>[F</td>
<td></td>
</tr>
<tr>
<td>double[]</td>
<td>jdoubleArray</td>
<td>[D</td>
<td></td>
</tr>
</tbody></table>
</li>
<li><p>对象引用类型</p>
<table>
<thead>
<tr>
<th>Java类型</th>
<th>Native类型</th>
<th>域描述符</th>
<th>补充</th>
</tr>
</thead>
<tbody><tr>
<td>Class</td>
<td>jobject</td>
<td>Lcom.example.Class;</td>
<td>以<code>"L"</code>开头,以<code>";"</code>结尾,内部类使用<code>"$"</code>连接,String除外</td>
</tr>
<tr>
<td>String</td>
<td>jstring</td>
<td>Ljava/lang/String;</td>
<td>唯一的例外</td>
</tr>
</tbody></table>
</li>
<li><p>对象数组引用类型</p>
<table>
<thead>
<tr>
<th>Java类型</th>
<th>Native类型</th>
<th>域描述符</th>
<th>补充</th>
</tr>
</thead>
<tbody><tr>
<td>Class</td>
<td>jobject</td>
<td>[Lcom.example.Class;</td>
<td>以<code>"[L"</code>开头,以<code>";"</code>结尾,内部类使用<code>"$"</code>连接,String除外</td>
</tr>
<tr>
<td>String</td>
<td>jstring</td>
<td>[Ljava/lang/String;</td>
<td>唯一的例外</td>
</tr>
</tbody></table>
</li>
</ul>
</li>
<li><p>JNI函数默认参数</p>
<ul>
<li><p>native方法默认参数<br> 普通的native方法,是Java类的成员方法,默认的参数有以下两个</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">JNIEnv *env, jobject thiz</span><br></pre></td></tr></table></figure>
<ul>
<li><p><code>JNIEnv *env</code></p>
<p> 指代当前的java环境,可以利用JNIEnv操作Java层代码</p>
</li>
<li><p><code>jobject thiz</code></p>
<p> 指代JNI函数对应的java native方法对应的类的实例</p>
</li>
</ul>
</li>
<li><p>static native方法默认参数<br> static native方法,是Java类的static方法,默认的参数有以下两个</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">JNIEnv *env, jclass classz</span><br></pre></td></tr></table></figure>
<ul>
<li><p><code>JNIEnv *env</code></p>
<p> 指代当前的java环境,可以利用JNIEnv操作Java层代码</p>
</li>
<li><p><code>jclass classz</code></p>
<p> 指代JNI函数对应的java static native方法对应的class对象</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>native-lib.cpp</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><jni.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义java层对应的package名称</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> JNIREG_CLASS <span class="meta-string">"com/example/MainActivity"</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Native方法实现</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> jstring <span class="title">stringFromJNI</span><span class="params">(JNIEnv *env, jclass classz)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> std::string hello = <span class="string">"Hello from C++"</span>;</span><br><span class="line"> <span class="keyword">return</span> env-><span class="built_in">NewStringUTF</span>(hello.<span class="built_in">c_str</span>());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Java层和Native层的方法签名</span></span><br><span class="line"><span class="keyword">static</span> JNINativeMethod nativeMethods[] = {</span><br><span class="line"> {<span class="string">"stringFromJNI"</span>, <span class="string">"()Ljava/lang/String;"</span>, (jstring *)stringFromJNI},</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// 注册native方法</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">register_native_methods</span><span class="params">(JNIEnv *env)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> jclass clazz = env-><span class="built_in">FindClass</span>(JNIREG_CLASS);</span><br><span class="line"> <span class="keyword">if</span> (clazz == <span class="literal">NULL</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">ALOGE</span>(<span class="string">"Native registeration unable to find class '%s'"</span>, JNIREG_CLASS);</span><br><span class="line"> <span class="keyword">return</span> JNI_FALSE;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (env-><span class="built_in">RegisterNatives</span>(clazz, nativeMethods, <span class="built_in"><span class="keyword">sizeof</span></span> (nativeMethods) / <span class="built_in"><span class="keyword">sizeof</span></span>(nativeMethods[<span class="number">0</span>])) < <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> env-><span class="built_in">DeleteLocalRef</span>(clazz);</span><br><span class="line"> <span class="built_in">ALOGE</span>(<span class="string">"RegisterNatives failed for '%s'"</span>, JNIREG_CLASS);</span><br><span class="line"> <span class="keyword">return</span> JNI_FALSE;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> JNI_TRUE;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 重写JNI_OnLoad方法</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> <span class="function">JNIEXPORT jint JNICALL <span class="title">JNI_OnLoad</span><span class="params">(JavaVM *vm, <span class="keyword">void</span> *reserved)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> JNIEnv *env = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="keyword">if</span> (vm-><span class="built_in">GetEnv</span>((<span class="keyword">void</span> **)&env, JNI_VERSION_1_6) != JNI_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> JNI_ERR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (JNI_TRUE != <span class="built_in">register_native_methods</span>(env))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> JNI_ERR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> JNI_VERSION_1_6;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="两种注册方法的对比"><a href="#两种注册方法的对比" class="headerlink" title="两种注册方法的对比"></a>两种注册方法的对比</h2><table>
<thead>
<tr>
<th>注册方法</th>
<th>优点</th>
<th>缺点</th>
</tr>
</thead>
<tbody><tr>
<td>静态注册</td>
<td>支持自动生成的IDE,可以比较方便的编写代码</td>
<td>在没有IDE自动生成的情况下,编写不方便</td>
</tr>
<tr>
<td>静态注册</td>
<td></td>
<td>程序运行效率低,每次调用native函数时,需要根据函数名在JNI层搜索对应的本地函数,建立对应关系,比较耗时</td>
</tr>