-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
436 lines (326 loc) · 25.4 KB
/
index.html
File metadata and controls
436 lines (326 loc) · 25.4 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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>BlakeY</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="description">
<meta property="og:type" content="website">
<meta property="og:title" content="BlakeY">
<meta property="og:url" content="http://blakey22.github.io/index.html">
<meta property="og:site_name" content="BlakeY">
<meta property="og:description">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="BlakeY">
<meta name="twitter:description">
<link rel="alternative" href="/atom.xml" title="BlakeY" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="/css/style.css" type="text/css">
<!-- Google Analytics -->
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-65674071-1', 'auto');
ga('send', 'pageview');
</script>
<!-- End Google Analytics -->
</head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">BlakeY</a>
</h1>
<h2 id="subtitle-wrap">
<a href="/" id="subtitle">Get busy living, or get busy dying.</a>
</h2>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
<a id="nav-search-btn" class="nav-icon" title="Search"></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://blakey22.github.io"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-Double-Tap-to-Wake-Nexus-6P" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/03/06/Double-Tap-to-Wake-Nexus-6P/" class="article-date">
<time datetime="2016-03-06T02:23:30.000Z" itemprop="datePublished">2016-03-06</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/03/06/Double-Tap-to-Wake-Nexus-6P/">Double Tap to Wake (Nexus 6P)</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="前言">前言</h1><p>把服役 3 年的蝴蝶機汰換成了 Google 的 Nexus 6P,依照阿宅工程師的一定要先 Root 在加裝 Xposed framework 的阿!一開始一切都很美好,直到我發現當把手機放在桌上想看時間,卻需要按下 Power 鍵來打開螢幕,而不是時下最流行的雙擊螢幕,心中的不滿不斷地增加…</p>
<h1 id="準備工作">準備工作</h1><p>在 XDA 這個開發者的大本營上找到了如何透過<a href="http://forum.xda-developers.com/showpost.php?p=63654097&postcount=45" target="_blank" rel="external">命令的方式</a>來開起雙擊螢幕的功能,自己也寫了一個簡單的 APP 來達成將下面的指令自動寫入系統。</p>
<figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo <span class="number">1</span> > <span class="regexp">/sys/</span>devices<span class="regexp">/soc.0/</span>f9924000.i2c<span class="regexp">/i2c-2/</span><span class="number">2</span>-<span class="number">0070</span><span class="regexp">/input/i</span>nput0<span class="regexp">/wake_gesture</span></span><br></pre></td></tr></table></figure>
<h1 id="那個_But">那個 But</h1><p>如同在其他文章都會遇到的情況,就是那個 But;APP 再重開機之後無法自動開啟這個功能,即使加入了 BOOT_COMPLETED 的 Receiver 也一樣,本來想著是可能是剛開機系統還沒有完全 Ready,需要多寫入幾次,但發現這樣是不行的…</p>
<pre><code>測試方法:
安裝 <span class="keyword">APP</span> 開啟雙擊功能,重開機後,不要按 Power 鍵或是掃描指紋,就這樣放著等幾分鐘,
你會發現雙擊功能還是沒辦法用,必須解鎖後重新執行 <span class="keyword">APP</span> 才可以。
</code></pre><h1 id="原因">原因</h1><p>經過調查,Double to Wake 的 Sensor 是屬於 Non-wake-up sensors,根據 <a href="https://source.android.com/devices/sensors/suspend-mode.html" target="_blank" rel="external">Google Android 說明</a> 指出:</p>
<pre><code>Non-wake-up sensors are sensors that <span class="operator"><span class="keyword">do</span> <span class="keyword">not</span> prevent the SoC <span class="keyword">from</span> going
<span class="keyword">into</span> suspend <span class="keyword">mode</span> <span class="keyword">and</span> <span class="keyword">do</span> <span class="keyword">not</span> wake the SoC up <span class="keyword">to</span> report <span class="keyword">data</span>.
<span class="keyword">In</span> particular, the drivers <span class="keyword">are</span> <span class="keyword">not</span> allowed <span class="keyword">to</span> hold wake-locks.</span>
</code></pre><p>簡單來說,當 SoC 處在 Suspend mode 之時,SoC 不會處理對應的事件(Event)。重開機之後的 Nexus 6P,預設的電源狀態是 Suspend mode,對應的 Sensor 也不會啟動,導致重開機後 APP 執行前述命令後,該設定仍然無法寫入到 Sensor,自然的 Double Tap to Wake 的功能就自動失效了。</p>
<h1 id="解決方案">解決方案</h1><ol>
<li>重新編譯 Kernel,重新定義 Sensor type</li>
<li>Boot completed 後,喚醒 APP 後讓 SoC 先進入 “On mode” 再執行前述命令</li>
</ol>
<p>最後採用了方案 2:簡單直接,同樣的這也有兩種方案可以選擇</p>
<ol>
<li>APP 使用 WakeUp lock 來喚醒 SoC</li>
<li>APP 模擬 Power Button 動作</li>
</ol>
<p>當然方案 2,還是我的首選 :p</p>
<h1 id="結論">結論</h1><p>廢話不多說 APP 與 Source Code 在這裡</p>
<ul>
<li><a href="https://play.google.com/store/apps/details?id=com.blakey22.doubletapwake" target="_blank" rel="external">APP</a></li>
<li><a href="https://github.com/blakey22/doubletapwake" target="_blank" rel="external">Source Code</a></li>
</ul>
<h1 id="參考文件">參考文件</h1><ul>
<li><a href="https://developer.android.com/reference/android/os/PowerManager.html" target="_blank" rel="external">https://developer.android.com/reference/android/os/PowerManager.html</a></li>
<li><a href="http://processors.wiki.ti.com/index.php/Android_Devkit_Power_Management_Porting_Guide" target="_blank" rel="external">http://processors.wiki.ti.com/index.php/Android_Devkit_Power_Management_Porting_Guide</a></li>
</ul>
</div>
<footer class="article-footer">
<a data-url="http://blakey22.github.io/2016/03/06/Double-Tap-to-Wake-Nexus-6P/" data-id="cilhmr8b6000004hljn795zh9" class="article-share-link">Share</a>
<a href="http://blakey22.github.io/2016/03/06/Double-Tap-to-Wake-Nexus-6P/#disqus_thread" class="article-comment-link">Comments</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Android/">Android</a></li></ul>
</footer>
</div>
</article>
<article id="post-Taiwan-bus-info" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2015/12/29/Taiwan-bus-info/" class="article-date">
<time datetime="2015-12-29T02:41:03.000Z" itemprop="datePublished">2015-12-29</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/12/29/Taiwan-bus-info/">台灣公車 Open Data</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="前言">前言</h1><p>最近有機會研究了一下台灣公車的 Open Data,發現各個縣市政府都是各自為政,相關的文件也是有不同程度的缺失,需要自行各個突破,幫自己做個記錄。</p>
<h1 id="公車必備資訊">公車必備資訊</h1><p>不管是哪個城市,公車都需要以下的資訊。</p>
<h3 id="路線">路線</h3><hr>
<ol>
<li>路線名稱</li>
<li>路線 ID</li>
<li>路線起點</li>
<li>路線終點</li>
</ol>
<h3 id="站牌">站牌</h3><hr>
<ol>
<li>站牌名稱</li>
<li>站牌 ID</li>
<li>站牌位置(經緯度)</li>
<li>站牌屬於去或回程</li>
<li>站牌在路線中的順序</li>
</ol>
<h3 id="預計到達時間">預計到達時間</h3><hr>
<ol>
<li>路線 ID</li>
<li>站牌 ID </li>
<li>站牌預計到達時間</li>
</ol>
<h1 id="台北市">台北市</h1><h3 id="資料來源:">資料來源:</h3><ul>
<li><a href="http://data.taipei/TPEOPD/opendata/datalist/datasetMeta/outboundDesc?id=7996eec3-e88a-4abc-b602-42c81932a9f6&rid=366f3d8a-e6bb-4d1c-8dac-af05911b411e" target="_blank" rel="external">路線</a></li>
<li><a href="http://data.taipei/opendata/datalist/datasetMeta/outboundDesc?id=48aa5bca-2a4f-4fb7-a658-43cba51d5d56&rid=7e71d313-e827-4314-8764-d5d5653ff5ee" target="_blank" rel="external">站牌</a></li>
<li><a href="http://www.dot.gov.taipei/ct.asp?xItem=3167481&CtNode=44829&mp=117001" target="_blank" rel="external">預計到達時間</a></li>
</ul>
<h3 id="資料格式:">資料格式:</h3><ul>
<li>JSON</li>
<li>XML</li>
</ul>
<h3 id="使用心得:">使用心得:</h3><p>主要的問題有 2 個:</p>
<ol>
<li>Open Data 的來源不一致是個問題,路線與站牌是一個,到站時間是另一個。</li>
<li>預計到達時間 API,不知為何針對單條路線進行查詢的時候,台北市政府的網站常常都會回應 Cache Miss,取而代之的就只能下載全部的路線的到站時間再做後置處理。</li>
</ol>
<h1 id="新北市">新北市</h1><h3 id="資料來源:-1">資料來源:</h3><ul>
<li><a href="http://data.ntpc.gov.tw/od/detail?oid=5D3B5FE3-549A-40D5-8FA3-0C691230B213" target="_blank" rel="external">路線</a></li>
<li><a href="http://data.ntpc.gov.tw/od/detail?oid=18621BF3-6B00-4A07-B49C-0C5CCABFE026" target="_blank" rel="external">站牌</a></li>
<li><a href="http://data.ntpc.gov.tw/od/detail?oid=CE74A94B-36D2-4482-A25D-670625ED0678" target="_blank" rel="external">預計到達時間</a></li>
</ul>
<h3 id="資料格式:-1">資料格式:</h3><ul>
<li>JSON</li>
<li>XML</li>
<li>CSV</li>
</ul>
<h3 id="使用心得:-1">使用心得:</h3><p>主要的問題有 3 個:</p>
<ol>
<li>路線的資料中沒有起點與終點站 Orz,雖然站牌的資料中是有路線的起點與終點,但是…是錯的!最後只能到新北市政府的公車動態網站抓資料了。</li>
<li>預計到達時間的單位是分鐘,台北市的單位是秒。</li>
<li>某些路線的預計到達時間的站牌 ID 竟然會與站牌 API 抓到的不一致,舉例來說站牌 API 回傳的站牌 ID 是 “801”,預計到達時間的站牌 ID 回傳的是 “0801” 我也真是無語了。</li>
</ol>
<h1 id="高雄市">高雄市</h1><h3 id="資料來源:-2">資料來源:</h3><ul>
<li><a href="http://data.kaohsiung.gov.tw/Opendata/DetailList.aspx?CaseNo1=AP&CaseNo2=33&Lang=C&FolderType=O" target="_blank" rel="external">路線</a></li>
<li><a href="http://data.kaohsiung.gov.tw/Opendata/DetailList.aspx?CaseNo1=AP&CaseNo2=36&Lang=C&FolderType=O" target="_blank" rel="external">站牌</a></li>
<li><a href="http://data.kaohsiung.gov.tw/Opendata/DetailList.aspx?CaseNo1=AP&CaseNo2=35&Lang=C&FolderType=O" target="_blank" rel="external">預計到達時間</a></li>
</ul>
<h3 id="資料格式:-2">資料格式:</h3><ul>
<li>XML</li>
<li>JSON (隱藏版)</li>
</ul>
<h3 id="使用心得:-2">使用心得:</h3><p>主要的問題有 3 個:</p>
<ol>
<li>預計到達時間是使用真實到站時間,比如說現在時間是 15:00,143 路線的車會再 3 分鐘後到達站牌 A,API 回傳的到站時間會是 15:03</li>
<li>站牌屬於去或回程的代碼相較於台北與新北市的有所不同 (0: 去, 1: 回),高雄市用得是另一組代碼 (1: 去, 2: 回) </li>
<li>Open Data 上有直接標明有 Json 格式的 API 只有一部分,但我又很不想爬 XML,經過了一番努力找到了公車的 JSON 版的資料,不過網站上都沒有標明這種做法,而且 JSON 格式也不是完全的正確,需要再後置處理。Json 版與 XML 版的 URL 就是差了幾個字 (xml => json),舉例取得公車站點資料的 URL 如下:</li>
</ol>
<p><strong>[XML]</strong></p>
<blockquote>
<p><a href="http://ibus.tbkc.gov.tw/xmlbus/StaticData/GetStop.xml?routeIds=111" target="_blank" rel="external">http://ibus.tbkc.gov.tw/xmlbus/StaticData/GetStop.xml?routeIds=111</a></p>
</blockquote>
<p><strong>[JSON]</strong></p>
<blockquote>
<p><a href="http://ibus.tbkc.gov.tw/xmlbus/StaticData/GetStop.json?routeIds=111" target="_blank" rel="external">http://ibus.tbkc.gov.tw/xmlbus/StaticData/GetStop.json?routeIds=111</a></p>
</blockquote>
<h1 id="總結">總結</h1><p>好像跟前言差不多,大概就是各個政府的 Open Data 說明文件都不是很齊全,都得開發人員自己想辦法去對照,還有格式也都不太統一,希望政府未來可以統籌規劃吧。</p>
</div>
<footer class="article-footer">
<a data-url="http://blakey22.github.io/2015/12/29/Taiwan-bus-info/" data-id="cilhmr8bh000304hlvhbo772z" class="article-share-link">Share</a>
<a href="http://blakey22.github.io/2015/12/29/Taiwan-bus-info/#disqus_thread" class="article-comment-link">Comments</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/OpenData/">OpenData</a></li></ul>
</footer>
</div>
</article>
<article id="post-Shadowsocks-for-Java" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2015/07/27/Shadowsocks-for-Java/" class="article-date">
<time datetime="2015-07-27T09:21:00.000Z" itemprop="datePublished">2015-07-27</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/07/27/Shadowsocks-for-Java/">Shadowsocks for Java</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="Preface">Preface</h1><p>自從來了大陸之後,VPN 就是日常必需品,經過了多次的血淚測試,證實 PPTP=容易被檔 IP,L2TP=速度太慢,目光轉向了新寵 <a href="https://github.com/shadowsocks/shadowsocks" target="_blank" rel="external">Shadowsocks</a>(以下簡稱 SS),用起來也都很愉快方便,瀏覽器跟手機都有對應的 Client 端可以使用,但不知為何在我的手機上效率很容易下滑,於是就想 trace 手機版 soure code (<a href="https://github.com/shadowsocks/shadowsocks-android" target="_blank" rel="external">shadowsocks-android</a>)來找原因,但發現他需要採用 NDK 的方式來編譯,這跟我想的有些出入,我以為 Java 就可以搞定了,於是就促使了下面研究。</p>
<h1 id="What’s_Shadowsocks?">What’s Shadowsocks?</h1><p>Shadowsocks 是個輕量化的自定義的 VPN 協定,封包格式是採用 Socks5 的 Header + 加密的 payload,其他細節可以參考網路上的其他說明。 </p>
<h1 id="Java_shadowsocks_client">Java shadowsocks client</h1><p>trace shadowsocks server 程式後,覺得寫一個純 Java 的 Client 應該不難,就是搞懂 Socks5 的 Protocol + 加密資料後送出,然後等待回應,解密。於是乎,問題回到了為何 shadowsocks-android 要用 NDK 來編譯,可能是原作者不想重造輪子,所以直接拿現成的 C 實作來兜,我自己有個猜測(後述),但令我好奇的是也沒有人寫出完整的 Java Client,<a href="https://blog.sorz.org/p/ss-java/" target="_blank" rel="external">唯一的找到實作</a>也被原作者捨棄了!?</p>
<p>想當然爾的,自己動手豐衣足食,正當覺得世界如此美好之時,Bug 隨之而來OOXX…只有第一次的 Request 會取得正確的 Response,之後的 Response 解密後都會是亂碼。在研究了七七四十九天後得到了以下的推論:</p>
<p><strong>Java 加密跟 Shadowsocks Server 不相容(我使用的是 AES-256-CFB 加密)</strong></p>
<p>Java 資料的加解密是有以下步驟,init、update、doFinal;而 SS 是把資料視為 Stream,除非 socket 中斷,不然就是一直處在 update 的步驟 (SS 用的是 OpenSSL),讓我們來看看 Java 的 Code</p>
<figure class="highlight java"><figcaption><span>update</span><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/com/sun/crypto/provider/CipherCore.java" target="_blank" rel="external">CipherCore.java</a></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">update</span><span class="params">(<span class="keyword">byte</span>[] input, <span class="keyword">int</span> inputOffset, <span class="keyword">int</span> inputLen, <span class="keyword">byte</span>[] output,</span><br><span class="line"> <span class="keyword">int</span> outputOffset)</span> <span class="keyword">throws</span> ShortBufferException </span>{</span><br><span class="line"> <span class="comment">// figure out how much can be sent to crypto function</span></span><br><span class="line"> <span class="keyword">int</span> len = buffered + inputLen - minBytes;</span><br><span class="line"> <span class="keyword">if</span> (padding != <span class="keyword">null</span> && decrypting) {</span><br><span class="line"> <span class="comment">// do not include the padding bytes when decrypting</span></span><br><span class="line"> len -= blockSize;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// do not count the trailing bytes which do not make up a unit</span></span><br><span class="line"> len = (len > <span class="number">0</span> ? (len - (len%unitBytes)) : <span class="number">0</span>);</span><br><span class="line"> ....</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>這樣乍看之下也沒有太大的問題,But,人生就是有這個 But,AES 是 Block cipher,換言之資料的加解密是以 Block (128 bit) 為單位進行,在 Java 的實作中,所以如果資料長度不到 128 bit,呼叫 update,Java 會把長度不夠的資料存在 buffer,不吐資料出來,舉個例子:</p>
<pre><code>SS Java Client Browser
|<span class="string">(1)-------------> </span>|<span class="string"> </span>|
|<span class="string"> </span>|<span class="string">-----+ </span>|
|<span class="string"> </span>|<span class="string">(2) </span>|<span class="string"> </span>|
|<span class="string"> </span>|<span class="string"><----+ </span>|
|<span class="string"> </span>|<span class="string"> </span>|<span class="string">(3)</span>
</code></pre><ol>
<li>SS 送出 5 bytes 給 Java Client</li>
<li>Java Client 進行解密,但因為長度不夠把資料暫存了起來</li>
<li>Browser 傻傻的在等待</li>
</ol>
<p>兇手在這裡,unitBytes 的 <a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/com/sun/crypto/provider/AESConstants.java#AESConstants.0AES_BLOCK_SIZE" target="_blank" rel="external">AES 常數定義</a></p>
<pre><code>len = <span class="list">(<span class="keyword">len</span> > <span class="number">0</span> ? <span class="list">(<span class="keyword">len</span> - <span class="list">(<span class="keyword">len</span>%unitBytes)</span>)</span> : <span class="number">0</span>)</span><span class="comment">;</span>
</code></pre><p>所以就是這樣囉,江湖一點訣,說破不值錢。</p>
<p>最後我用了 <a href="https://www.bouncycastle.org/" target="_blank" rel="external">Bouncy Castle</a> 來繞過原生的 Java 限制。 可以在 Github 上找到我的 <a href="https://github.com/blakey22/shadowsocks-java" target="_blank" rel="external">shadowsocks-java</a>。</p>
<h1 id="Why_NDK?">Why NDK?</h1><p>差點忘了,為何 Android 版的需要用 NDK,撇去 SS client 的部分,我猜是因為沒有 Java 版的 tun2socks…XD</p>
<p>以上,打包收工。</p>
</div>
<footer class="article-footer">
<a data-url="http://blakey22.github.io/2015/07/27/Shadowsocks-for-Java/" data-id="cilhmr8jn000604hlxlxtme3x" class="article-share-link">Share</a>
<a href="http://blakey22.github.io/2015/07/27/Shadowsocks-for-Java/#disqus_thread" class="article-comment-link">Comments</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/shadowsocks/">shadowsocks</a></li></ul>
</footer>
</div>
</article>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">Tags</h3>
<div class="widget">
<ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android/">Android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/OpenData/">OpenData</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/shadowsocks/">shadowsocks</a><span class="tag-list-count">1</span></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Tag Cloud</h3>
<div class="widget tagcloud">
<a href="/tags/Android/" style="font-size: 10px;">Android</a> <a href="/tags/OpenData/" style="font-size: 10px;">OpenData</a> <a href="/tags/shadowsocks/" style="font-size: 10px;">shadowsocks</a>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Archives</h3>
<div class="widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/03/">March 2016</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/07/">July 2015</a><span class="archive-list-count">1</span></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Recents</h3>
<div class="widget">
<ul>
<li>
<a href="/2016/03/06/Double-Tap-to-Wake-Nexus-6P/">Double Tap to Wake (Nexus 6P)</a>
</li>
<li>
<a href="/2015/12/29/Taiwan-bus-info/">台灣公車 Open Data</a>
</li>
<li>
<a href="/2015/07/27/Shadowsocks-for-Java/">Shadowsocks for Java</a>
</li>
</ul>
</div>
</div>
</aside>
</div>
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
© 2016 blakey22<br>
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
</div>
</div>
</footer>
</div>
<nav id="mobile-nav">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/archives" class="mobile-nav-link">Archives</a>
</nav>
<script>
var disqus_shortname = 'blakey22';
(function(){
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
<script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>
<script src="/js/script.js" type="text/javascript"></script>
</div>
</body>
</html>