| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.content.common; | |
| 6 | |
| 7 import android.text.TextUtils; | |
| 8 import android.util.Log; | |
| 9 | |
| 10 import java.io.File; | |
| 11 import java.io.FileInputStream; | |
| 12 import java.io.FileNotFoundException; | |
| 13 import java.io.IOException; | |
| 14 import java.io.InputStreamReader; | |
| 15 import java.io.Reader; | |
| 16 import java.util.ArrayList; | |
| 17 import java.util.Arrays; | |
| 18 import java.util.HashMap; | |
| 19 import java.util.concurrent.atomic.AtomicReference; | |
| 20 | |
| 21 /** | |
| 22 * Java mirror of Chrome command-line utilities (e.g. class CommandLine from bas
e/command_line.h). | |
| 23 * Command line program adb_command_line can be used to set the Chrome command l
ine: | |
| 24 * adb shell "echo chrome --my-param > /data/local/chrome-command-line" | |
| 25 */ | |
| 26 public abstract class CommandLine { | |
| 27 // Block onCreate() of Chrome until a Java debugger is attached. | |
| 28 public static final String WAIT_FOR_JAVA_DEBUGGER = "wait-for-java-debugger"
; | |
| 29 | |
| 30 // Tell Java to use the official command line, loaded from the | |
| 31 // official-command-line.xml files. WARNING this is not done | |
| 32 // immediately on startup, so early running Java code will not see | |
| 33 // these flags. | |
| 34 public static final String ADD_OFFICIAL_COMMAND_LINE = "add-official-command
-line"; | |
| 35 | |
| 36 // Enables test intent handling. | |
| 37 public static final String ENABLE_TEST_INTENTS = "enable-test-intents"; | |
| 38 | |
| 39 // Adds additional thread idle time information into the trace event output. | |
| 40 public static final String ENABLE_IDLE_TRACING = "enable-idle-tracing"; | |
| 41 | |
| 42 // Dump frames-per-second to the log | |
| 43 public static final String LOG_FPS = "log-fps"; | |
| 44 | |
| 45 // Whether Chromium should use a mobile user agent. | |
| 46 public static final String USE_MOBILE_UA = "use-mobile-user-agent"; | |
| 47 | |
| 48 // tablet specific UI components. | |
| 49 // Native switch - chrome_switches::kTabletUI | |
| 50 public static final String TABLET_UI = "tablet-ui"; | |
| 51 | |
| 52 // Change the url of the JavaScript that gets injected when accessibility mo
de is enabled. | |
| 53 public static final String ACCESSIBILITY_JAVASCRIPT_URL = "accessibility-js-
url"; | |
| 54 | |
| 55 public static final String ACCESSIBILITY_DEBUG_BRAILLE_SERVICE = "debug-brai
lle-service"; | |
| 56 | |
| 57 // Sets the ISO country code that will be used for phone number detection. | |
| 58 public static final String NETWORK_COUNTRY_ISO = "network-country-iso"; | |
| 59 | |
| 60 // Whether to enable the auto-hiding top controls. | |
| 61 public static final String ENABLE_TOP_CONTROLS_POSITION_CALCULATION | |
| 62 = "enable-top-controls-position-calculation"; | |
| 63 | |
| 64 // The height of the movable top controls. | |
| 65 public static final String TOP_CONTROLS_HEIGHT = "top-controls-height"; | |
| 66 | |
| 67 // How much of the top controls need to be shown before they will auto show. | |
| 68 public static final String TOP_CONTROLS_SHOW_THRESHOLD = "top-controls-show-
threshold"; | |
| 69 | |
| 70 // How much of the top controls need to be hidden before they will auto hide
. | |
| 71 public static final String TOP_CONTROLS_HIDE_THRESHOLD = "top-controls-hide-
threshold"; | |
| 72 | |
| 73 // Native switch - chrome_switches::kEnableInstantExtendedAPI | |
| 74 public static final String ENABLE_INSTANT_EXTENDED_API = "enable-instant-ext
ended-api"; | |
| 75 | |
| 76 // Native switch - content_switches::kEnableSpeechRecognition | |
| 77 public static final String ENABLE_SPEECH_RECOGNITION = "enable-speech-recogn
ition"; | |
| 78 | |
| 79 // Native switch - shell_switches::kDumpRenderTree | |
| 80 public static final String DUMP_RENDER_TREE = "dump-render-tree"; | |
| 81 | |
| 82 // Native switch - chrome_switches::kDisablePopupBlocking | |
| 83 public static final String DISABLE_POPUP_BLOCKING = "disable-popup-blocking"
; | |
| 84 | |
| 85 // Whether to disable the click delay by sending click events during double
tap | |
| 86 public static final String DISABLE_CLICK_DELAY = "disable-click-delay"; | |
| 87 | |
| 88 // Public abstract interface, implemented in derived classes. | |
| 89 // All these methods reflect their native-side counterparts. | |
| 90 /** | |
| 91 * Returns true if this command line contains the given switch. | |
| 92 * (Switch names ARE case-sensitive). | |
| 93 */ | |
| 94 public abstract boolean hasSwitch(String switchString); | |
| 95 | |
| 96 /** | |
| 97 * Return the value associated with the given switch, or null. | |
| 98 * @param switchString The switch key to lookup. It should NOT start with '-
-' ! | |
| 99 * @return switch value, or null if the switch is not set or set to empty. | |
| 100 */ | |
| 101 public abstract String getSwitchValue(String switchString); | |
| 102 | |
| 103 /** | |
| 104 * Return the value associated with the given switch, or {@code defaultValue
} if the switch | |
| 105 * was not specified. | |
| 106 * @param switchString The switch key to lookup. It should NOT start with '-
-' ! | |
| 107 * @param defaultValue The default value to return if the switch isn't set. | |
| 108 * @return Switch value, or {@code defaultValue} if the switch is not set or
set to empty. | |
| 109 */ | |
| 110 public String getSwitchValue(String switchString, String defaultValue) { | |
| 111 String value = getSwitchValue(switchString); | |
| 112 return TextUtils.isEmpty(value) ? defaultValue : value; | |
| 113 } | |
| 114 | |
| 115 /** | |
| 116 * Append a switch to the command line. There is no guarantee | |
| 117 * this action happens before the switch is needed. | |
| 118 * @param switchString the switch to add. It should NOT start with '--' ! | |
| 119 */ | |
| 120 public abstract void appendSwitch(String switchString); | |
| 121 | |
| 122 /** | |
| 123 * Append a switch and value to the command line. There is no | |
| 124 * guarantee this action happens before the switch is needed. | |
| 125 * @param switchString the switch to add. It should NOT start with '--' ! | |
| 126 * @param value the value for this switch. | |
| 127 * For example, --foo=bar becomes 'foo', 'bar'. | |
| 128 */ | |
| 129 public abstract void appendSwitchWithValue(String switchString, String value
); | |
| 130 | |
| 131 /** | |
| 132 * Append switch/value items in "command line" format (excluding argv[0] pro
gram name). | |
| 133 * E.g. { '--gofast', '--username=fred' } | |
| 134 * @param array an array of switch or switch/value items in command line for
mat. | |
| 135 * Unlike the other append routines, these switches SHOULD start with '--'
. | |
| 136 * Unlike init(), this does not include the program name in array[0]. | |
| 137 */ | |
| 138 public abstract void appendSwitchesAndArguments(String[] array); | |
| 139 | |
| 140 /** | |
| 141 * Determine if the command line is bound to the native (JNI) implementation
. | |
| 142 * @return true if the underlying implementation is delegating to the native
command line. | |
| 143 */ | |
| 144 public boolean isNativeImplementation() { | |
| 145 return false; | |
| 146 } | |
| 147 | |
| 148 private static final AtomicReference<CommandLine> sCommandLine = | |
| 149 new AtomicReference<CommandLine>(); | |
| 150 | |
| 151 /** | |
| 152 * @returns true if the command line has already been initialized. | |
| 153 */ | |
| 154 public static boolean isInitialized() { | |
| 155 return sCommandLine.get() != null; | |
| 156 } | |
| 157 | |
| 158 // Equivalent to CommandLine::ForCurrentProcess in C++. | |
| 159 public static CommandLine getInstance() { | |
| 160 CommandLine commandLine = sCommandLine.get(); | |
| 161 assert commandLine != null; | |
| 162 return commandLine; | |
| 163 } | |
| 164 | |
| 165 /** | |
| 166 * Initialize the singleton instance, must be called exactly once (either di
rectly or | |
| 167 * via one of the convenience wrappers below) before using the static single
ton instance. | |
| 168 * @param args command line flags in 'argv' format: args[0] is the program n
ame. | |
| 169 */ | |
| 170 public static void init(String[] args) { | |
| 171 setInstance(new JavaCommandLine(args)); | |
| 172 } | |
| 173 | |
| 174 /** | |
| 175 * Initialize the command line from the command-line file. | |
| 176 * | |
| 177 * @param file The fully qualified command line file. | |
| 178 */ | |
| 179 public static void initFromFile(String file) { | |
| 180 // Arbitrary clamp of 8k on the amount of file we read in. | |
| 181 char[] buffer = readUtf8FileFully(file, 8 * 1024); | |
| 182 init(buffer == null ? null : tokenizeQuotedAruments(buffer)); | |
| 183 } | |
| 184 | |
| 185 /** | |
| 186 * Resets both the java proxy and the native command lines. This allows the
entire | |
| 187 * command line initialization to be re-run including the call to onJniLoade
d. | |
| 188 */ | |
| 189 public static void reset() { | |
| 190 setInstance(null); | |
| 191 } | |
| 192 | |
| 193 /** | |
| 194 * Public for testing (TODO: why are the tests in a different package?) | |
| 195 * Parse command line flags from a flat buffer, supporting double-quote encl
osed strings | |
| 196 * containing whitespace. argv elements are derived by splitting the buffer
on whitepace; | |
| 197 * double quote characters may enclose tokens containing whitespace; a doubl
e-quote literal | |
| 198 * may be escaped with back-slash. (Otherwise backslash is taken as a litera
l). | |
| 199 * @param buffer A command line in command line file format as described abo
ve. | |
| 200 * @return the tokenized arguments, suitable for passing to init(). | |
| 201 */ | |
| 202 public static String[] tokenizeQuotedAruments(char[] buffer) { | |
| 203 ArrayList<String> args = new ArrayList<String>(); | |
| 204 StringBuilder arg = null; | |
| 205 final char noQuote = '\0'; | |
| 206 final char singleQuote = '\''; | |
| 207 final char doubleQuote = '"'; | |
| 208 char currentQuote = noQuote; | |
| 209 for (char c : buffer) { | |
| 210 // Detect start or end of quote block. | |
| 211 if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuot
e)) || | |
| 212 c == currentQuote) { | |
| 213 if (arg != null && arg.length() > 0 && arg.charAt(arg.length() -
1) == '\\') { | |
| 214 // Last char was a backslash; pop it, and treat c as a liter
al. | |
| 215 arg.setCharAt(arg.length() - 1, c); | |
| 216 } else { | |
| 217 currentQuote = currentQuote == noQuote ? c : noQuote; | |
| 218 } | |
| 219 } else if (currentQuote == noQuote && Character.isWhitespace(c)) { | |
| 220 if (arg != null) { | |
| 221 args.add(arg.toString()); | |
| 222 arg = null; | |
| 223 } | |
| 224 } else { | |
| 225 if (arg == null) arg = new StringBuilder(); | |
| 226 arg.append(c); | |
| 227 } | |
| 228 } | |
| 229 if (arg != null) { | |
| 230 if (currentQuote != noQuote) { | |
| 231 Log.w(TAG, "Unterminated quoted string: " + arg); | |
| 232 } | |
| 233 args.add(arg.toString()); | |
| 234 } | |
| 235 return args.toArray(new String[args.size()]); | |
| 236 } | |
| 237 | |
| 238 private static final String TAG = "CommandLine"; | |
| 239 private static final String SWITCH_PREFIX = "--"; | |
| 240 private static final String SWITCH_TERMINATOR = SWITCH_PREFIX; | |
| 241 private static final String SWITCH_VALUE_SEPARATOR = "="; | |
| 242 | |
| 243 public static void enableNativeProxy() { | |
| 244 // Make a best-effort to ensure we make a clean (atomic) switch over fro
m the old to | |
| 245 // the new command line implementation. If another thread is modifying t
he command line | |
| 246 // when this happens, all bets are off. (As per the native CommandLine). | |
| 247 sCommandLine.set(new NativeCommandLine()); | |
| 248 } | |
| 249 | |
| 250 public static String[] getJavaSwitchesOrNull() { | |
| 251 CommandLine commandLine = sCommandLine.get(); | |
| 252 if (commandLine != null) { | |
| 253 assert !commandLine.isNativeImplementation(); | |
| 254 return ((JavaCommandLine) commandLine).getCommandLineArguments(); | |
| 255 } | |
| 256 return null; | |
| 257 } | |
| 258 | |
| 259 private static void setInstance(CommandLine commandLine) { | |
| 260 CommandLine oldCommandLine = sCommandLine.getAndSet(commandLine); | |
| 261 if (oldCommandLine != null && oldCommandLine.isNativeImplementation()) { | |
| 262 nativeReset(); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 /** | |
| 267 * @param fileName the file to read in. | |
| 268 * @param sizeLimit cap on the file size. | |
| 269 * @return Array of chars read from the file, or null if the file cannot be
read | |
| 270 * or if its length exceeds |sizeLimit|. | |
| 271 */ | |
| 272 private static char[] readUtf8FileFully(String fileName, int sizeLimit) { | |
| 273 Reader reader = null; | |
| 274 File f = new File(fileName); | |
| 275 long fileLength = f.length(); | |
| 276 | |
| 277 if (fileLength == 0) { | |
| 278 return null; | |
| 279 } | |
| 280 | |
| 281 if (fileLength > sizeLimit) { | |
| 282 Log.w(TAG, "File " + fileName + " length " + fileLength + " exceeds
limit " | |
| 283 + sizeLimit); | |
| 284 return null; | |
| 285 } | |
| 286 | |
| 287 try { | |
| 288 char[] buffer = new char[(int) fileLength]; | |
| 289 reader = new InputStreamReader(new FileInputStream(f), "UTF-8"); | |
| 290 int charsRead = reader.read(buffer); | |
| 291 // Debug check that we've exhausted the input stream (will fail e.g.
if the | |
| 292 // file grew after we inspected its length). | |
| 293 assert !reader.ready(); | |
| 294 return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, cha
rsRead) : buffer; | |
| 295 } catch (FileNotFoundException e) { | |
| 296 return null; | |
| 297 } catch (IOException e) { | |
| 298 return null; | |
| 299 } finally { | |
| 300 try { | |
| 301 if (reader != null) reader.close(); | |
| 302 } catch (IOException e) { | |
| 303 Log.e(TAG, "Unable to close file reader.", e); | |
| 304 } | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 private CommandLine() {} | |
| 309 | |
| 310 private static class JavaCommandLine extends CommandLine { | |
| 311 private HashMap<String, String> mSwitches = new HashMap<String, String>(
); | |
| 312 private ArrayList<String> mArgs = new ArrayList<String>(); | |
| 313 | |
| 314 // The arguments begin at index 1, since index 0 contains the executable
name. | |
| 315 private int mArgsBegin = 1; | |
| 316 | |
| 317 JavaCommandLine(String[] args) { | |
| 318 if (args == null || args.length == 0 || args[0] == null) { | |
| 319 mArgs.add(""); | |
| 320 } else { | |
| 321 mArgs.add(args[0]); | |
| 322 appendSwitchesInternal(args, 1); | |
| 323 } | |
| 324 // Invariant: we always have the argv[0] program name element. | |
| 325 assert mArgs.size() > 0; | |
| 326 } | |
| 327 | |
| 328 /** | |
| 329 * Returns the switches and arguments passed into the program, with swit
ches and their | |
| 330 * values coming before all of the arguments. | |
| 331 */ | |
| 332 private String[] getCommandLineArguments() { | |
| 333 return mArgs.toArray(new String[mArgs.size()]); | |
| 334 } | |
| 335 | |
| 336 @Override | |
| 337 public boolean hasSwitch(String switchString) { | |
| 338 return mSwitches.containsKey(switchString); | |
| 339 } | |
| 340 | |
| 341 @Override | |
| 342 public String getSwitchValue(String switchString) { | |
| 343 // This is slightly round about, but needed for consistency with the
NativeCommandLine | |
| 344 // version which does not distinguish empty values from key not pres
ent. | |
| 345 String value = mSwitches.get(switchString); | |
| 346 return value == null || value.isEmpty() ? null : value; | |
| 347 } | |
| 348 | |
| 349 @Override | |
| 350 public void appendSwitch(String switchString) { | |
| 351 appendSwitchWithValue(switchString, null); | |
| 352 } | |
| 353 | |
| 354 /** | |
| 355 * Appends a switch to the current list. | |
| 356 * @param switchString the switch to add. It should NOT start with '--'
! | |
| 357 * @param value the value for this switch. | |
| 358 */ | |
| 359 @Override | |
| 360 public void appendSwitchWithValue(String switchString, String value) { | |
| 361 mSwitches.put(switchString, value == null ? "" : value); | |
| 362 | |
| 363 // Append the switch and update the switches/arguments divider mArgs
Begin. | |
| 364 String combinedSwitchString = SWITCH_PREFIX + switchString; | |
| 365 if (value != null && !value.isEmpty()) | |
| 366 combinedSwitchString += SWITCH_VALUE_SEPARATOR + value; | |
| 367 | |
| 368 mArgs.add(mArgsBegin++, combinedSwitchString); | |
| 369 } | |
| 370 | |
| 371 @Override | |
| 372 public void appendSwitchesAndArguments(String[] array) { | |
| 373 appendSwitchesInternal(array, 0); | |
| 374 } | |
| 375 | |
| 376 // Add the specified arguments, but skipping the first |skipCount| eleme
nts. | |
| 377 private void appendSwitchesInternal(String[] array, int skipCount) { | |
| 378 boolean parseSwitches = true; | |
| 379 for (String arg : array) { | |
| 380 if (skipCount > 0) { | |
| 381 --skipCount; | |
| 382 continue; | |
| 383 } | |
| 384 | |
| 385 if (arg.equals(SWITCH_TERMINATOR)) { | |
| 386 parseSwitches = false; | |
| 387 } | |
| 388 | |
| 389 if (parseSwitches && arg.startsWith(SWITCH_PREFIX)) { | |
| 390 String[] parts = arg.split(SWITCH_VALUE_SEPARATOR, 2); | |
| 391 String value = parts.length > 1 ? parts[1] : null; | |
| 392 appendSwitchWithValue(parts[0].substring(SWITCH_PREFIX.lengt
h()), value); | |
| 393 } else { | |
| 394 mArgs.add(arg); | |
| 395 } | |
| 396 } | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 private static class NativeCommandLine extends CommandLine { | |
| 401 @Override | |
| 402 public boolean hasSwitch(String switchString) { | |
| 403 return nativeHasSwitch(switchString); | |
| 404 } | |
| 405 | |
| 406 @Override | |
| 407 public String getSwitchValue(String switchString) { | |
| 408 return nativeGetSwitchValue(switchString); | |
| 409 } | |
| 410 | |
| 411 @Override | |
| 412 public void appendSwitch(String switchString) { | |
| 413 nativeAppendSwitch(switchString); | |
| 414 } | |
| 415 | |
| 416 @Override | |
| 417 public void appendSwitchWithValue(String switchString, String value) { | |
| 418 nativeAppendSwitchWithValue(switchString, value); | |
| 419 } | |
| 420 | |
| 421 @Override | |
| 422 public void appendSwitchesAndArguments(String[] array) { | |
| 423 nativeAppendSwitchesAndArguments(array); | |
| 424 } | |
| 425 | |
| 426 @Override | |
| 427 public boolean isNativeImplementation() { | |
| 428 return true; | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 private static native void nativeReset(); | |
| 433 private static native boolean nativeHasSwitch(String switchString); | |
| 434 private static native String nativeGetSwitchValue(String switchString); | |
| 435 private static native void nativeAppendSwitch(String switchString); | |
| 436 private static native void nativeAppendSwitchWithValue(String switchString,
String value); | |
| 437 private static native void nativeAppendSwitchesAndArguments(String[] array); | |
| 438 }; | |
| OLD | NEW |