// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.content.browser; import android.app.ActivityManager; import android.content.Context; import android.content.res.Resources; import android.util.Log; import org.chromium.base.JNINamespace; import org.chromium.content.app.ContentMain; import org.chromium.content.app.LibraryLoader; import org.chromium.content.browser.PepperPluginManager; import org.chromium.content.common.CommandLine; import org.chromium.content.common.ProcessInitException; // NOTE: This file hasn't been fully upstreamed, please don't merge to downstream. @JNINamespace("content") public class AndroidBrowserProcess { private static final String TAG = "BrowserProcessMain"; // Prevents initializing the process more than once. private static boolean sInitialized = false; // Computes the actual max renderer processes used. private static int normalizeMaxRendererProcesses(Context context, int maxRendererProcesses) { if (maxRendererProcesses == MAX_RENDERERS_AUTOMATIC) { // We use the device's memory class to decide the maximum renderer // processes. For the baseline devices the memory class is 16 and we will // limit it to one render process. For the devices with memory class 24, // we allow two render processes. ActivityManager am = (ActivityManager)context.getSystemService( Context.ACTIVITY_SERVICE); maxRendererProcesses = Math.max(((am.getMemoryClass() - 8) / 8), 1); } if (maxRendererProcesses > MAX_RENDERERS_LIMIT) { Log.w(TAG, "Excessive maxRendererProcesses value: " + maxRendererProcesses); return MAX_RENDERERS_LIMIT; } return Math.max(0, maxRendererProcesses); } // Automatically decide the number of renderer processes to use based on device memory class. public static final int MAX_RENDERERS_AUTOMATIC = -1; // Use single-process mode that runs the renderer on a separate thread in the main application. public static final int MAX_RENDERERS_SINGLE_PROCESS = 0; // Cap on the maximum number of renderer processes that can be requested. // This is currently set to account for: // 6: The maximum number of sandboxed processes we have available // - 1: The regular New Tab Page // - 1: The incognito New Tab Page // - 1: A regular incognito tab public static final int MAX_RENDERERS_LIMIT = ChildProcessLauncher.MAX_REGISTERED_SANDBOXED_SERVICES - 3; /** * Initialize the process as a ContentView host. This must be called from the main UI thread. * This should be called by the ContentView constructor to prepare this process for ContentView * use outside of the browser. In the case where ContentView is used in the browser then * initBrowserProcess() should already have been called and this is a no-op. * * @param context Context used to obtain the application context. * @param maxRendererProcesses Limit on the number of renderers to use. Each tab runs in its own * process until the maximum number of processes is reached. The special value of * MAX_RENDERERS_SINGLE_PROCESS requests single-process mode where the renderer will run in the * application process in a separate thread. If the special value MAX_RENDERERS_AUTOMATIC is * used then the number of renderers will be determined based on the device memory class. The * maximum number of allowed renderers is capped by MAX_RENDERERS_LIMIT. * @return Whether the process actually needed to be initialized (false if already running). */ public static boolean init(Context context, int maxRendererProcesses) throws ProcessInitException { if (sInitialized) return false; sInitialized = true; // Normally Main.java will have kicked this off asynchronously for Chrome. But // other ContentView apps like tests also need them so we make sure we've // extracted resources here. We can still make it a little async (wait until // the library is loaded). ResourceExtractor resourceExtractor = ResourceExtractor.get(context); resourceExtractor.startExtractingResources(); // Normally Main.java will have already loaded the library asynchronously, we only // need to load it here if we arrived via another flow, e.g. bookmark access & sync setup. LibraryLoader.ensureInitialized(); Context appContext = context.getApplicationContext(); int maxRenderers = normalizeMaxRendererProcesses(appContext, maxRendererProcesses); Log.i(TAG, "Initializing chromium process, renderers=" + maxRenderers); // Now we really need to have the resources ready. resourceExtractor.waitForCompletion(); nativeSetCommandLineFlags(maxRenderers, nativeIsPluginEnabled() ? getPlugins(context) : null); ContentMain.initApplicationContext(appContext); int result = ContentMain.start(); if (result > 0) throw new ProcessInitException(result); return true; } /** * Initialization needed for tests. Mainly used by content browsertests. */ public static void initChromiumBrowserProcessForTests(Context context) { ResourceExtractor resourceExtractor = ResourceExtractor.get(context); resourceExtractor.startExtractingResources(); resourceExtractor.waitForCompletion(); // Having a single renderer should be sufficient for tests. // We can't have more than MAX_RENDERERS_LIMIT. nativeSetCommandLineFlags(1 /* maxRenderers */, null); } private static String getPlugins(final Context context) { return PepperPluginManager.getPlugins(context); } private static native void nativeSetCommandLineFlags(int maxRenderProcesses, String pluginDescriptor); // Is this an official build of Chrome? Only native code knows // for sure. Official build knowledge is needed very early in // process startup. private static native boolean nativeIsOfficialBuild(); private static native boolean nativeIsPluginEnabled(); }