// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/aw_render_process.h"
#include "android_webview/common/aw_features.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "ipc/ipc_channel_proxy.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "android_webview/browser_jni_headers/AwRenderProcess_jni.h"
using base::android::AttachCurrentThread;
using content::BrowserThread;
using content::ChildProcessTerminationInfo;
using content::RenderProcessHost;
namespace android_webview {
const void* const kAwRenderProcessKey = &kAwRenderProcessKey;
// A user data key to keep track of whether a render view has been created in
// this RPH. This can't be stored in AwRenderProcess since that object may be
// deleted if the OS process dies.
const void* const kAwRenderViewReadyKey = &kAwRenderViewReadyKey;
// static
AwRenderProcess* AwRenderProcess::GetInstanceForRenderProcessHost(
RenderProcessHost* host) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
AwRenderProcess* render_process =
static_cast<AwRenderProcess*>(host->GetUserData(kAwRenderProcessKey));
if (!render_process) {
std::unique_ptr<AwRenderProcess> created_render_process =
std::make_unique<AwRenderProcess>(host);
render_process = created_render_process.get();
host->SetUserData(kAwRenderProcessKey, std::move(created_render_process));
}
return render_process;
}
AwRenderProcess::AwRenderProcess(RenderProcessHost* render_process_host)
: render_process_host_(render_process_host) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
java_obj_.Reset(Java_AwRenderProcess_create(AttachCurrentThread()));
CHECK(java_obj_);
if (render_process_host_->IsReady()) {
Ready();
}
GetRendererRemote();
render_process_host->AddObserver(this);
}
AwRenderProcess::~AwRenderProcess() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
Java_AwRenderProcess_setNative(AttachCurrentThread(), java_obj_, 0);
java_obj_.Reset();
}
void AwRenderProcess::ClearCache() {
GetRendererRemote()->ClearCache();
}
void AwRenderProcess::SetJsOnlineProperty(bool network_up) {
GetRendererRemote()->SetJsOnlineProperty(network_up);
}
// static
void AwRenderProcess::SetRenderViewReady(content::RenderProcessHost* host) {
host->SetUserData(kAwRenderViewReadyKey,
std::make_unique<base::SupportsUserData::Data>());
}
// static
bool AwRenderProcess::IsUnused(content::RenderProcessHost* host) {
return host->IsUnused() && !host->GetUserData(kAwRenderViewReadyKey);
}
void AwRenderProcess::Ready() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
Java_AwRenderProcess_setNative(AttachCurrentThread(), java_obj_,
reinterpret_cast<jlong>(this));
}
void AwRenderProcess::Cleanup() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// If the process was never used, keep the same Java object to satisfy CTS
// tests.
if (base::FeatureList::IsEnabled(
features::kCreateSpareRendererOnBrowserContextCreation) &&
IsUnused(render_process_host_)) {
renderer_remote_.reset();
return;
}
render_process_host_->RemoveObserver(this);
render_process_host_->RemoveUserData(kAwRenderProcessKey);
// |this| is now deleted.
}
bool AwRenderProcess::TerminateChildProcess(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
bool result = render_process_host_->Shutdown(0);
// If the process has never been used, this is the spare render process.
// Treat this as if it never existed since it's an internal performance
// optimization.
if (base::FeatureList::IsEnabled(
features::kCreateSpareRendererOnBrowserContextCreation) &&
result && IsUnused(render_process_host_)) {
// Use fast shutdown for the unused process to allow loadUrl() calls to work
// immediately after the terminate call.
render_process_host_->FastShutdownIfPossible();
return false;
}
return result;
}
bool AwRenderProcess::IsProcessLockedToSiteForTesting(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return render_process_host_->IsProcessLockedToSiteForTesting(); // IN-TEST
}
base::android::ScopedJavaLocalRef<jobject> AwRenderProcess::GetJavaObject() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return base::android::ScopedJavaLocalRef<jobject>(java_obj_);
}
void AwRenderProcess::RenderProcessReady(RenderProcessHost* host) {
DCHECK(host == render_process_host_);
Ready();
}
void AwRenderProcess::RenderProcessExited(
RenderProcessHost* host,
const ChildProcessTerminationInfo& info) {
DCHECK(host == render_process_host_);
Cleanup();
}
mojom::Renderer* AwRenderProcess::GetRendererRemote() {
if (!renderer_remote_) {
render_process_host_->GetChannel()->GetRemoteAssociatedInterface(
&renderer_remote_);
renderer_remote_.reset_on_disconnect();
}
return renderer_remote_.get();
}
} // namespace android_webview