1 // Copyright 2015 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.base; 6 7 import android.annotation.SuppressLint; 8 import android.content.Context; 9 import android.os.Build; 10 import android.provider.Settings; 11 12 import org.chromium.base.annotations.SuppressFBWarnings; 13 14 import java.io.File; 15 16 /** 17 * Provides implementation of command line initialization for Android. 18 */ 19 public final class CommandLineInitUtil { 20 21 private static final String TAG = "CommandLineInitUtil"; 22 23 /** 24 * The location of the command line file needs to be in a protected 25 * directory so requires root access to be tweaked, i.e., no other app in a 26 * regular (non-rooted) device can change this file's contents. 27 * See below for debugging on a regular (non-rooted) device. 28 */ 29 private static final String COMMAND_LINE_FILE_PATH = "/data/local"; 30 31 /** 32 * This path (writable by the shell in regular non-rooted "user" builds) is used when: 33 * 1) The "debug app" is set to the application calling this. 34 * and 35 * 2) ADB is enabled. 36 * 37 */ 38 private static final String COMMAND_LINE_FILE_PATH_DEBUG_APP = "/data/local/tmp"; 39 CommandLineInitUtil()40 private CommandLineInitUtil() { 41 } 42 43 /** 44 * Initializes the CommandLine class, pulling command line arguments from {@code fileName}. 45 * @param context The {@link Context} to use to query whether or not this application is being 46 * debugged, and whether or not the publicly writable command line file should 47 * be used. 48 * @param fileName The name of the command line file to pull arguments from. 49 */ 50 @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME") initCommandLine(Context context, String fileName)51 public static void initCommandLine(Context context, String fileName) { 52 if (!CommandLine.isInitialized()) { 53 File commandLineFile = getAlternativeCommandLinePath(context, fileName); 54 if (commandLineFile == null) { 55 commandLineFile = new File(COMMAND_LINE_FILE_PATH, fileName); 56 } 57 CommandLine.initFromFile(commandLineFile.getPath()); 58 } 59 } 60 61 /** 62 * Use an alternative path if adb is enabled and this is the debug app. 63 */ 64 @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME") getAlternativeCommandLinePath(Context context, String fileName)65 private static File getAlternativeCommandLinePath(Context context, String fileName) { 66 File alternativeCommandLineFile = 67 new File(COMMAND_LINE_FILE_PATH_DEBUG_APP, fileName); 68 if (!alternativeCommandLineFile.exists()) return null; 69 try { 70 String debugApp = Build.VERSION.SDK_INT < 17 71 ? getDebugAppPreJBMR1(context) : getDebugAppJBMR1(context); 72 73 if (debugApp != null 74 && debugApp.equals(context.getApplicationContext().getPackageName())) { 75 Log.i(TAG, "Using alternative command line file in " 76 + alternativeCommandLineFile.getPath()); 77 return alternativeCommandLineFile; 78 } 79 } catch (RuntimeException e) { 80 Log.e(TAG, "Unable to detect alternative command line file"); 81 } 82 83 return null; 84 } 85 86 @SuppressLint("NewApi") 87 private static String getDebugAppJBMR1(Context context) { 88 boolean adbEnabled = Settings.Global.getInt(context.getContentResolver(), 89 Settings.Global.ADB_ENABLED, 0) == 1; 90 if (adbEnabled) { 91 return Settings.Global.getString(context.getContentResolver(), 92 Settings.Global.DEBUG_APP); 93 } 94 return null; 95 } 96 97 @SuppressWarnings("deprecation") 98 private static String getDebugAppPreJBMR1(Context context) { 99 boolean adbEnabled = Settings.System.getInt(context.getContentResolver(), 100 Settings.System.ADB_ENABLED, 0) == 1; 101 if (adbEnabled) { 102 return Settings.System.getString(context.getContentResolver(), 103 Settings.System.DEBUG_APP); 104 } 105 return null; 106 } 107 } 108