15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.content.common; 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.text.TextUtils; 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log; 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.File; 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.FileInputStream; 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.FileNotFoundException; 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.IOException; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.InputStreamReader; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.Reader; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.ArrayList; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Arrays; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.HashMap; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.concurrent.atomic.AtomicReference; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Java mirror of Chrome command-line utilities (e.g. class CommandLine from base/command_line.h). 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Command line program adb_command_line can be used to set the Chrome command line: 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * adb shell "echo chrome --my-param > /data/local/chrome-command-line" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public abstract class CommandLine { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Block onCreate() of Chrome until a Java debugger is attached. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String WAIT_FOR_JAVA_DEBUGGER = "wait-for-java-debugger"; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Tell Java to use the official command line, loaded from the 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // official-command-line.xml files. WARNING this is not done 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // immediately on startup, so early running Java code will not see 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // these flags. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String ADD_OFFICIAL_COMMAND_LINE = "add-official-command-line"; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enables test intent handling. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String ENABLE_TEST_INTENTS = "enable-test-intents"; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dump frames-per-second to the log 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String LOG_FPS = "log-fps"; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Whether Chromium should use a mobile user agent. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String USE_MOBILE_UA = "use-mobile-user-agent"; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tablet specific UI components. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Native switch - chrome_switches::kTabletUI 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String TABLET_UI = "tablet-ui"; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Change the url of the JavaScript that gets injected when accessibility mode is enabled. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String ACCESSIBILITY_JAVASCRIPT_URL = "accessibility-js-url"; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String ACCESSIBILITY_DEBUG_BRAILLE_SERVICE = "debug-braille-service"; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets the ISO country code that will be used for phone number detection. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String NETWORK_COUNTRY_ISO = "network-country-iso"; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Whether to enable the auto-hiding top controls. 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String ENABLE_TOP_CONTROLS_POSITION_CALCULATION 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) = "enable-top-controls-position-calculation"; 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The height of the movable top controls. 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String TOP_CONTROLS_HEIGHT = "top-controls-height"; 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // How much of the top controls need to be shown before they will auto show. 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String TOP_CONTROLS_SHOW_THRESHOLD = "top-controls-show-threshold"; 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // How much of the top controls need to be hidden before they will auto hide. 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String TOP_CONTROLS_HIDE_THRESHOLD = "top-controls-hide-threshold"; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Native switch - chrome_switches::kEnableInstantExtendedAPI 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public static final String ENABLE_INSTANT_EXTENDED_API = "enable-instant-extended-api"; 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Native switch - content_switches::kEnableSpeechRecognition 74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public static final String ENABLE_SPEECH_RECOGNITION = "enable-speech-recognition"; 75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Native switch - shell_switches::kDumpRenderTree 773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch public static final String DUMP_RENDER_TREE = "dump-render-tree"; 783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Public abstract interface, implemented in derived classes. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All these methods reflect their native-side counterparts. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns true if this command line contains the given switch. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (Switch names ARE case-sensitive). 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public abstract boolean hasSwitch(String switchString); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return the value associated with the given switch, or null. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param switchString The switch key to lookup. It should NOT start with '--' ! 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return switch value, or null if the switch is not set or set to empty. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public abstract String getSwitchValue(String switchString); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return the value associated with the given switch, or {@code defaultValue} if the switch 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * was not specified. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param switchString The switch key to lookup. It should NOT start with '--' ! 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param defaultValue The default value to return if the switch isn't set. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return Switch value, or {@code defaultValue} if the switch is not set or set to empty. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public String getSwitchValue(String switchString, String defaultValue) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String value = getSwitchValue(switchString); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TextUtils.isEmpty(value) ? defaultValue : value; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Append a switch to the command line. There is no guarantee 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this action happens before the switch is needed. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param switchString the switch to add. It should NOT start with '--' ! 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public abstract void appendSwitch(String switchString); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Append a switch and value to the command line. There is no 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * guarantee this action happens before the switch is needed. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param switchString the switch to add. It should NOT start with '--' ! 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param value the value for this switch. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * For example, --foo=bar becomes 'foo', 'bar'. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public abstract void appendSwitchWithValue(String switchString, String value); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Append switch/value items in "command line" format (excluding argv[0] program name). 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * E.g. { '--gofast', '--username=fred' } 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param array an array of switch or switch/value items in command line format. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unlike the other append routines, these switches SHOULD start with '--' . 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unlike init(), this does not include the program name in array[0]. 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public abstract void appendSwitchesAndArguments(String[] array); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Determine if the command line is bound to the native (JNI) implementation. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return true if the underlying implementation is delegating to the native command line. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public boolean isNativeImplementation() { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final AtomicReference<CommandLine> sCommandLine = 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new AtomicReference<CommandLine>(); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @returns true if the command line has already been initialized. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static boolean isInitialized() { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sCommandLine.get() != null; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Equivalent to CommandLine::ForCurrentProcess in C++. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static CommandLine getInstance() { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine commandLine = sCommandLine.get(); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert commandLine != null; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return commandLine; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initialize the singleton instance, must be called exactly once (either directly or 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * via one of the convenience wrappers below) before using the static singleton instance. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param args command line flags in 'argv' format: args[0] is the program name. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static void init(String[] args) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setInstance(new JavaCommandLine(args)); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initialize the command line from the command-line file. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param file The fully qualified command line file. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static void initFromFile(String file) { 171558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch // Arbitrary clamp of 8k on the amount of file we read in. 172558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch char[] buffer = readUtf8FileFully(file, 8 * 1024); 173558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch init(buffer == null ? null : tokenizeQuotedAruments(buffer)); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Resets both the java proxy and the native command lines. This allows the entire 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * command line initialization to be re-run including the call to onJniLoaded. 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static void reset() { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setInstance(null); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Public for testing (TODO: why are the tests in a different package?) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Parse command line flags from a flat buffer, supporting double-quote enclosed strings 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * containing whitespace. argv elements are derived by splitting the buffer on whitepace; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * double quote characters may enclose tokens containing whitespace; a double-quote literal 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * may be escaped with back-slash. (Otherwise backslash is taken as a literal). 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param buffer A command line in command line file format as described above. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return the tokenized arguments, suitable for passing to init(). 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static String[] tokenizeQuotedAruments(char[] buffer) { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ArrayList<String> args = new ArrayList<String>(); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringBuilder arg = null; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final char noQuote = '\0'; 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final char singleQuote = '\''; 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final char doubleQuote = '"'; 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char currentQuote = noQuote; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (char c : buffer) { 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Detect start or end of quote block. 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuote)) || 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) c == currentQuote) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (arg != null && arg.length() > 0 && arg.charAt(arg.length() - 1) == '\\') { 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Last char was a backslash; pop it, and treat c as a literal. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arg.setCharAt(arg.length() - 1, c); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) currentQuote = currentQuote == noQuote ? c : noQuote; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (currentQuote == noQuote && Character.isWhitespace(c)) { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (arg != null) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args.add(arg.toString()); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arg = null; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (arg == null) arg = new StringBuilder(); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arg.append(c); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (arg != null) { 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (currentQuote != noQuote) { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Log.w(TAG, "Unterminated quoted string: " + arg); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args.add(arg.toString()); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return args.toArray(new String[args.size()]); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final String TAG = "CommandLine"; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final String SWITCH_PREFIX = "--"; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final String SWITCH_TERMINATOR = SWITCH_PREFIX; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final String SWITCH_VALUE_SEPARATOR = "="; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static void enableNativeProxy() { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make a best-effort to ensure we make a clean (atomic) switch over from the old to 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the new command line implementation. If another thread is modifying the command line 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when this happens, all bets are off. (As per the native CommandLine). 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sCommandLine.set(new NativeCommandLine()); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static String[] getJavaSwitchesOrNull() { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine commandLine = sCommandLine.get(); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (commandLine != null) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert !commandLine.isNativeImplementation(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((JavaCommandLine) commandLine).getCommandLineArguments(); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return null; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static void setInstance(CommandLine commandLine) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine oldCommandLine = sCommandLine.getAndSet(commandLine); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (oldCommandLine != null && oldCommandLine.isNativeImplementation()) { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nativeReset(); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param fileName the file to read in. 259558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param sizeLimit cap on the file size. 260558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @return Array of chars read from the file, or null if the file cannot be read 261558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * or if its length exceeds |sizeLimit|. 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 263558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch private static char[] readUtf8FileFully(String fileName, int sizeLimit) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Reader reader = null; 265558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch File f = new File(fileName); 266558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch long fileLength = f.length(); 267558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch 268558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if (fileLength == 0) { 269558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return null; 270558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch } 271558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch 272558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if (fileLength > sizeLimit) { 273558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch Log.w(TAG, "File " + fileName + " length " + fileLength + " exceeds limit " 274558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch + sizeLimit); 275558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return null; 276558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch } 277558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 279558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch char[] buffer = new char[(int) fileLength]; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader = new InputStreamReader(new FileInputStream(f), "UTF-8"); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int charsRead = reader.read(buffer); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Debug check that we've exhausted the input stream (will fail e.g. if the 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // file grew after we inspected its length). 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert !reader.ready(); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer; 286558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch } catch (FileNotFoundException e) { 287558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return null; 288558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch } catch (IOException e) { 289558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return null; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } finally { 291558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch try { 292558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if (reader != null) reader.close(); 293558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch } catch (IOException e) { 294558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch Log.e(TAG, "Unable to close file reader.", e); 295558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch } 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private CommandLine() {} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static class JavaCommandLine extends CommandLine { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private HashMap<String, String> mSwitches = new HashMap<String, String>(); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private ArrayList<String> mArgs = new ArrayList<String>(); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The arguments begin at index 1, since index 0 contains the executable name. 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private int mArgsBegin = 1; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JavaCommandLine(String[] args) { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (args == null || args.length == 0 || args[0] == null) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mArgs.add(""); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mArgs.add(args[0]); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) appendSwitchesInternal(args, 1); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Invariant: we always have the argv[0] program name element. 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert mArgs.size() > 0; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns the switches and arguments passed into the program, with switches and their 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * values coming before all of the arguments. 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private String[] getCommandLineArguments() { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mArgs.toArray(new String[mArgs.size()]); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public boolean hasSwitch(String switchString) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mSwitches.containsKey(switchString); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public String getSwitchValue(String switchString) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is slightly round about, but needed for consistency with the NativeCommandLine 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // version which does not distinguish empty values from key not present. 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String value = mSwitches.get(switchString); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value == null || value.isEmpty() ? null : value; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void appendSwitch(String switchString) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) appendSwitchWithValue(switchString, null); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Appends a switch to the current list. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param switchString the switch to add. It should NOT start with '--' ! 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param value the value for this switch. 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void appendSwitchWithValue(String switchString, String value) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mSwitches.put(switchString, value == null ? "" : value); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append the switch and update the switches/arguments divider mArgsBegin. 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String combinedSwitchString = SWITCH_PREFIX + switchString; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value != null && !value.isEmpty()) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) combinedSwitchString += SWITCH_VALUE_SEPARATOR + value; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mArgs.add(mArgsBegin++, combinedSwitchString); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void appendSwitchesAndArguments(String[] array) { 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) appendSwitchesInternal(array, 0); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the specified arguments, but skipping the first |skipCount| elements. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private void appendSwitchesInternal(String[] array, int skipCount) { 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean parseSwitches = true; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (String arg : array) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (skipCount > 0) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --skipCount; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (arg.equals(SWITCH_TERMINATOR)) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parseSwitches = false; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parseSwitches && arg.startsWith(SWITCH_PREFIX)) { 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String[] parts = arg.split(SWITCH_VALUE_SEPARATOR, 2); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String value = parts.length > 1 ? parts[1] : null; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) appendSwitchWithValue(parts[0].substring(SWITCH_PREFIX.length()), value); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mArgs.add(arg); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static class NativeCommandLine extends CommandLine { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public boolean hasSwitch(String switchString) { 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nativeHasSwitch(switchString); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public String getSwitchValue(String switchString) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nativeGetSwitchValue(switchString); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void appendSwitch(String switchString) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nativeAppendSwitch(switchString); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void appendSwitchWithValue(String switchString, String value) { 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nativeAppendSwitchWithValue(switchString, value); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void appendSwitchesAndArguments(String[] array) { 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nativeAppendSwitchesAndArguments(array); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public boolean isNativeImplementation() { 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static native void nativeReset(); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static native boolean nativeHasSwitch(String switchString); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static native String nativeGetSwitchValue(String switchString); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static native void nativeAppendSwitch(String switchString); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static native void nativeAppendSwitchWithValue(String switchString, String value); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static native void nativeAppendSwitchesAndArguments(String[] array); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 430