1// Copyright 2014 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
5package org.chromium.chromecast.shell;
6
7import android.app.Activity;
8import android.content.Context;
9import android.content.Intent;
10import android.os.Build;
11import android.os.Debug;
12import android.util.Log;
13
14import org.chromium.base.BaseSwitches;
15import org.chromium.base.CommandLine;
16import org.chromium.base.library_loader.LibraryLoader;
17import org.chromium.base.library_loader.ProcessInitException;
18import org.chromium.content.browser.BrowserStartupController;
19import org.chromium.content.browser.DeviceUtils;
20import org.chromium.content.common.ContentSwitches;
21
22/**
23 * Static, one-time initialization for the browser process.
24 */
25public class CastBrowserHelper {
26    private static final String TAG = "CastBrowserHelper";
27
28    public static final String COMMAND_LINE_FILE = "/data/local/tmp/castshell-command-line";
29    public static final String COMMAND_LINE_ARGS_KEY = "commandLineArgs";
30
31    private static boolean sIsBrowserInitialized = false;
32
33    /**
34     * Starts the browser process synchronously, returning success or failure. If the browser has
35     * already started, immediately returns true without performing any more initialization.
36     * This may only be called on the UI thread.
37     *
38     * @return whether or not the process started successfully
39     */
40    public static boolean initializeBrowser(Context context) {
41        if (sIsBrowserInitialized) return true;
42
43        Log.d(TAG, "Performing one-time browser initialization");
44
45        // Initializing the command line must occur before loading the library.
46        if (!CommandLine.isInitialized()) {
47            if (allowCommandLineImport()) {
48                Log.d(TAG, "Initializing command line from " + COMMAND_LINE_FILE);
49                CommandLine.initFromFile(COMMAND_LINE_FILE);
50            } else {
51                CommandLine.init(null);
52            }
53
54            if (context instanceof Activity) {
55                Intent launchingIntent = ((Activity) context).getIntent();
56                String[] commandLineParams = getCommandLineParamsFromIntent(launchingIntent);
57                if (commandLineParams != null) {
58                    CommandLine.getInstance().appendSwitchesAndArguments(commandLineParams);
59                }
60            }
61        }
62
63        CommandLine.getInstance().appendSwitchWithValue(
64                ContentSwitches.FORCE_DEVICE_SCALE_FACTOR, "1");
65
66        waitForDebuggerIfNeeded();
67
68        DeviceUtils.addDeviceSpecificUserAgentSwitch(context);
69
70        try {
71            LibraryLoader.ensureInitialized();
72
73            Log.d(TAG, "Loading BrowserStartupController...");
74            BrowserStartupController.get(context).startBrowserProcessesSync(false);
75
76            sIsBrowserInitialized = true;
77            return true;
78        } catch (ProcessInitException e) {
79            Log.e(TAG, "Unable to launch browser process.", e);
80            return false;
81        }
82    }
83
84    private static boolean allowCommandLineImport() {
85      return !Build.TYPE.equals("user");
86    }
87
88    private static String[] getCommandLineParamsFromIntent(Intent intent) {
89        return intent != null ? intent.getStringArrayExtra(COMMAND_LINE_ARGS_KEY) : null;
90    }
91
92    private static void waitForDebuggerIfNeeded() {
93        if (!CommandLine.getInstance().hasSwitch(BaseSwitches.WAIT_FOR_JAVA_DEBUGGER)) {
94            return;
95        }
96        Log.e(TAG, "Waiting for Java debugger to connect...");
97        Debug.waitForDebugger();
98        Log.e(TAG, "Java debugger connected. Resuming execution.");
99    }
100}
101