chromium/android_webview/browser/aw_render_process.cc

// 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