blob: afbb48899d5b1eb4ebc6c5eac93c673b8e0e8834 [file] [log] [blame]
// Copyright 2017 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.app;
import android.content.Context;
import android.content.Intent;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Surface;
import org.chromium.base.CommandLine;
import org.chromium.base.JNIUtils;
import org.chromium.base.Log;
import org.chromium.base.UnguessableToken;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.Linker;
import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.base.process_launcher.ChildProcessCreationParams;
import org.chromium.content.browser.ChildProcessConstants;
import org.chromium.content.common.ContentSwitches;
import org.chromium.content.common.IGpuProcessCallback;
import org.chromium.content.common.SurfaceWrapper;
import org.chromium.content_public.common.ContentProcessInfo;
/**
* This implementation of {@link ChildProcessServiceDelegate} loads the native library potentially
* using the custom linker, provides access to view surfaces.
*/
@JNINamespace("content")
@MainDex
public class ContentChildProcessServiceDelegate implements ChildProcessServiceDelegate {
private static final String TAG = "ContentCPSDelegate";
// Linker-specific parameters for this child process service.
private ChromiumLinkerParams mLinkerParams;
// Child library process type.
private int mLibraryProcessType;
private IGpuProcessCallback mGpuCallback;
private int mCpuCount;
private long mCpuFeatures;
@Override
public void onServiceCreated() {
ContentProcessInfo.setInChildProcess(true);
}
@Override
public void onServiceBound(Intent intent) {
mLinkerParams = (ChromiumLinkerParams) intent.getParcelableExtra(
ChildProcessConstants.EXTRA_LINKER_PARAMS);
mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessType(intent);
}
@Override
public void onConnectionSetup(Bundle connectionBundle, IBinder callback) {
mGpuCallback = callback != null ? IGpuProcessCallback.Stub.asInterface(callback) : null;
mCpuCount = connectionBundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT);
mCpuFeatures = connectionBundle.getLong(ChildProcessConstants.EXTRA_CPU_FEATURES);
assert mCpuCount > 0;
Bundle sharedRelros = connectionBundle.getBundle(Linker.EXTRA_LINKER_SHARED_RELROS);
if (sharedRelros != null) {
getLinker().useSharedRelros(sharedRelros);
sharedRelros = null;
}
}
@Override
public boolean loadNativeLibrary(Context hostContext) {
String processType =
CommandLine.getInstance().getSwitchValue(ContentSwitches.SWITCH_PROCESS_TYPE);
if (ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) {
JNIUtils.enableSelectiveJniRegistration();
}
Linker linker = null;
boolean requestedSharedRelro = false;
if (Linker.isUsed()) {
assert mLinkerParams != null;
linker = getLinker();
if (mLinkerParams.mWaitForSharedRelro) {
requestedSharedRelro = true;
linker.initServiceProcess(mLinkerParams.mBaseLoadAddress);
} else {
linker.disableSharedRelros();
}
}
LibraryLoader libraryLoader = null;
boolean isLoaded = false;
boolean loadAtFixedAddressFailed = false;
try {
libraryLoader = LibraryLoader.get(mLibraryProcessType);
libraryLoader.loadNowOverrideApplicationContext(hostContext);
isLoaded = true;
} catch (ProcessInitException e) {
if (requestedSharedRelro) {
Log.w(TAG,
"Failed to load native library with shared RELRO, "
+ "retrying without");
loadAtFixedAddressFailed = true;
} else {
Log.e(TAG, "Failed to load native library", e);
}
}
if (!isLoaded && libraryLoader != null && requestedSharedRelro) {
linker.disableSharedRelros();
try {
libraryLoader.loadNowOverrideApplicationContext(hostContext);
isLoaded = true;
} catch (ProcessInitException e) {
Log.e(TAG, "Failed to load native library on retry", e);
}
}
if (!isLoaded) {
return false;
}
libraryLoader.registerRendererProcessHistogram(
requestedSharedRelro, loadAtFixedAddressFailed);
try {
libraryLoader.initialize();
} catch (ProcessInitException e) {
Log.w(TAG, "startup failed: %s", e);
return false;
}
return true;
}
@Override
public void onBeforeMain() {
nativeInitChildProcess(mCpuCount, mCpuFeatures);
}
@Override
public void onDestroy() {
// Try to shutdown the MainThread gracefully, but it might not have a
// chance to exit normally.
nativeShutdownMainThread();
}
@Override
public void runMain() {
ContentMain.start();
}
// Return a Linker instance. If testing, the Linker needs special setup.
private Linker getLinker() {
if (Linker.areTestsEnabled()) {
// For testing, set the Linker implementation and the test runner
// class name to match those used by the parent.
assert mLinkerParams != null;
Linker.setupForTesting(mLinkerParams.mLinkerImplementationForTesting,
mLinkerParams.mTestRunnerClassNameForTesting);
}
return Linker.getInstance();
}
@SuppressWarnings("unused")
@CalledByNative
private void forwardSurfaceTextureForSurfaceRequest(
UnguessableToken requestToken, SurfaceTexture surfaceTexture) {
if (mGpuCallback == null) {
Log.e(TAG, "No callback interface has been provided.");
return;
}
Surface surface = new Surface(surfaceTexture);
try {
mGpuCallback.forwardSurfaceForSurfaceRequest(requestToken, surface);
} catch (RemoteException e) {
Log.e(TAG, "Unable to call forwardSurfaceForSurfaceRequest: %s", e);
return;
} finally {
surface.release();
}
}
@SuppressWarnings("unused")
@CalledByNative
private Surface getViewSurface(int surfaceId) {
if (mGpuCallback == null) {
Log.e(TAG, "No callback interface has been provided.");
return null;
}
try {
SurfaceWrapper wrapper = mGpuCallback.getViewSurface(surfaceId);
return wrapper != null ? wrapper.getSurface() : null;
} catch (RemoteException e) {
Log.e(TAG, "Unable to call getViewSurface: %s", e);
return null;
}
}
/**
* Initializes the native parts of the service.
*
* @param serviceImpl This ChildProcessServiceImpl object.
* @param cpuCount The number of CPUs.
* @param cpuFeatures The CPU features.
*/
private native void nativeInitChildProcess(int cpuCount, long cpuFeatures);
private native void nativeShutdownMainThread();
}