189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang/* 289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Copyright (C) 2011 The Android Open Source Project 389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * 489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Licensed under the Apache License, Version 2.0 (the "License"); 589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * you may not use this file except in compliance with the License. 689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * You may obtain a copy of the License at 789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * 889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * http://www.apache.org/licenses/LICENSE-2.0 989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * 1089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Unless required by applicable law or agreed to in writing, software 1189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * distributed under the License is distributed on an "AS IS" BASIS, 1289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * See the License for the specific language governing permissions and 1489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * limitations under the License. 1589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */ 1689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangpackage com.android.tests.bandwidthenforcement; 1789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 1889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.app.IntentService; 1989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.content.Intent; 2089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.net.SntpClient; 2189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.os.Environment; 2289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.util.Log; 2389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 2489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.BufferedWriter; 2589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.ByteArrayOutputStream; 2689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.File; 2789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.FileWriter; 2889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.IOException; 2989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.InputStreamReader; 3089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.DatagramPacket; 3189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.DatagramSocket; 3289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.HttpURLConnection; 3389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.InetAddress; 3489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.URL; 3589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.util.Random; 3689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 3789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport libcore.io.Streams; 3889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 3989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang/* 4089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Test Service that tries to connect to the web via different methods and outputs the results to 4189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * the log and a output file. 4289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */ 4389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangpublic class BandwidthEnforcementTestService extends IntentService { 4489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang private static final String TAG = "BandwidthEnforcementTestService"; 4589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang private static final String OUTPUT_FILE = "BandwidthEnforcementTestServiceOutputFile"; 4689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 4789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang public BandwidthEnforcementTestService() { 4889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang super(TAG); 4989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 5089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 5189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang @Override 5289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang protected void onHandleIntent(Intent intent) { 5389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.d(TAG, "Trying to establish a connection."); 5489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang // Read output file path from intent. 5589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang String outputFile = intent.getStringExtra(OUTPUT_FILE); 5689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang dumpResult("testUrlConnection", testUrlConnection(), outputFile); 5789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang dumpResult("testUrlConnectionv6", testUrlConnectionv6(), outputFile); 5889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang dumpResult("testSntp", testSntp(), outputFile); 5989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang dumpResult("testDns", testDns(), outputFile); 6089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 6189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 6289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang public static void dumpResult(String tag, boolean result, String outputFile) { 6389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.d(TAG, "Test output file: " + outputFile); 6489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang try { 6589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang if (outputFile != null){ 6689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang File extStorage = Environment.getExternalStorageDirectory(); 6789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang File outFile = new File(extStorage, outputFile); 6889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang FileWriter writer = new FileWriter(outFile, true); 6989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang BufferedWriter out = new BufferedWriter(writer); 7089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang if (result) { 7189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.append(tag + ":fail\n"); 7289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } else { 7389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.append(tag + ":pass\n"); 7489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 7589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.close(); 7689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 7789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang if (result) { 7889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.e(TAG, tag + " FAILURE ===================="); 7989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.e(TAG, tag + " FAILURE was able to use data"); 8089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.e(TAG, tag + " FAILURE ===================="); 8189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } else { 8289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.d(TAG, tag + " success; unable to use data"); 8389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 8489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } catch (IOException e) { 8589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.e(TAG, "Could not write file " + e.getMessage()); 8689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 8789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 8889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 8989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang /** 9089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Tests a normal http url connection. 9189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * @return true if it was able to connect, false otherwise. 9289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */ 9389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang public static boolean testUrlConnection() { 9489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang try { 9589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final HttpURLConnection conn = (HttpURLConnection) new URL("http://www.google.com/") 9689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang .openConnection(); 9789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang try { 9889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang conn.connect(); 9989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final String content = Streams.readFully( 10089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang new InputStreamReader(conn.getInputStream())); 10189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang if (content.contains("Google")) { 10289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return true; 10389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 10489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } finally { 10589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang conn.disconnect(); 10689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 10789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } catch (IOException e) { 10889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.d(TAG, "error: " + e); 10989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 11089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return false; 11189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 11289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 11389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang /** 11489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Tests a ipv6 http url connection. 11589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * @return true if it was able to connect, false otherwise. 11689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */ 11789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang public static boolean testUrlConnectionv6() { 11889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang try { 11989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final HttpURLConnection conn = (HttpURLConnection) new URL("http://ipv6.google.com/") 12089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang .openConnection(); 12189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang try { 12289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang conn.connect(); 12389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final String content = Streams.readFully( 12489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang new InputStreamReader(conn.getInputStream())); 12589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang if (content.contains("Google")) { 12689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return true; 12789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 12889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } finally { 12989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang conn.disconnect(); 13089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 13189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } catch (IOException e) { 13289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.d(TAG, "error: " + e); 13389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 13489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return false; 13589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 13689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 13789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang /** 13889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Tests to connect via sntp. 13989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * @return true if it was able to connect, false otherwise. 14089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */ 14189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang public static boolean testSntp() { 14289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final SntpClient client = new SntpClient(); 14389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang if (client.requestTime("0.pool.ntp.org", 10000)) { 14489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return true; 14589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 14689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return false; 14789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 14889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 14989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang /** 15089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Tests dns query. 15189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * @return true if it was able to connect, false otherwise. 15289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */ 15389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang public static boolean testDns() { 15489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang try { 15589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final DatagramSocket socket = new DatagramSocket(); 15689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang try { 15789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang socket.setSoTimeout(10000); 15889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 15989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final byte[] query = buildDnsQuery("www", "android", "com"); 16089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final DatagramPacket queryPacket = new DatagramPacket( 16189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang query, query.length, InetAddress.parseNumericAddress("8.8.8.8"), 53); 16289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang socket.send(queryPacket); 16389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 16489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final byte[] reply = new byte[query.length]; 16589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final DatagramPacket replyPacket = new DatagramPacket(reply, reply.length); 16689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang socket.receive(replyPacket); 16789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return true; 16889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 16989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } finally { 17089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang socket.close(); 17189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 17289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } catch (IOException e) { 17389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang Log.d(TAG, "error: " + e); 17489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 17589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return false; 17689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 17789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 17889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang /** 17989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Helper method to build a dns query 18089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * @param query the dns strings of the server 18189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * @return the byte array of the dns query to send 18289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * @throws IOException 18389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */ 18489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang private static byte[] buildDnsQuery(String... query) throws IOException { 18589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final Random random = new Random(); 18689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final ByteArrayOutputStream out = new ByteArrayOutputStream(); 18789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 18889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final byte[] id = new byte[2]; 18989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang random.nextBytes(id); 19089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 19189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(id); 19289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(new byte[] { 0x01, 0x00 }); 19389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(new byte[] { 0x00, 0x01 }); 19489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(new byte[] { 0x00, 0x00 }); 19589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(new byte[] { 0x00, 0x00 }); 19689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(new byte[] { 0x00, 0x00 }); 19789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 19889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang for (String phrase : query) { 19989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang final byte[] bytes = phrase.getBytes("US-ASCII"); 20089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(bytes.length); 20189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(bytes); 20289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 20389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(0x00); 20489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 20589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(new byte[] { 0x00, 0x01 }); 20689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang out.write(new byte[] { 0x00, 0x01 }); 20789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang 20889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang return out.toByteArray(); 20989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang } 21089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang} 211