1// Copyright (c) 2012 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
5#include <jni.h>
6#include <vector>
7
8#include "base/android/jni_android.h"
9#include "base/android/jni_string.h"
10#include "base/android/scoped_java_ref.h"
11#include "base/basictypes.h"
12#include "base/lazy_instance.h"
13#include "base/logging.h"
14#include "content/browser/android/content_view_statics.h"
15#include "content/common/android/address_parser.h"
16#include "content/common/view_messages.h"
17#include "content/public/browser/render_process_host.h"
18#include "content/public/browser/render_process_host_observer.h"
19#include "jni/ContentViewStatics_jni.h"
20
21using base::android::ConvertJavaStringToUTF16;
22using base::android::ConvertUTF16ToJavaString;
23
24namespace {
25
26// TODO(pliard): http://crbug.com/235909. Move WebKit shared timer toggling
27// functionality out of ContentViewStatistics and not be build on top of
28// blink::Platform::SuspendSharedTimer.
29// TODO(pliard): http://crbug.com/235912. Add unit tests for WebKit shared timer
30// toggling.
31
32// This tracks the renderer processes that received a suspend request. It's
33// important on resume to only resume the renderer processes that were actually
34// suspended as opposed to all the current renderer processes because the
35// suspend calls are refcounted within WebKitPlatformSupport and it expects a
36// perfectly matched number of resume calls.
37// Note that this class is only accessed from the UI thread.
38class SuspendedProcessWatcher : public content::RenderProcessHostObserver {
39 public:
40
41  // If the process crashes, stop watching the corresponding RenderProcessHost
42  // and ensure it doesn't get over-resumed.
43  virtual void RenderProcessExited(content::RenderProcessHost* host,
44                                   base::ProcessHandle handle,
45                                   base::TerminationStatus status,
46                                   int exit_code) OVERRIDE {
47    StopWatching(host);
48  }
49
50  virtual void RenderProcessHostDestroyed(
51      content::RenderProcessHost* host) OVERRIDE {
52    StopWatching(host);
53  }
54
55  // Suspends timers in all current render processes.
56  void SuspendWebKitSharedTimers() {
57    DCHECK(suspended_processes_.empty());
58
59    for (content::RenderProcessHost::iterator i(
60            content::RenderProcessHost::AllHostsIterator());
61         !i.IsAtEnd(); i.Advance()) {
62      content::RenderProcessHost* host = i.GetCurrentValue();
63      host->AddObserver(this);
64      host->Send(new ViewMsg_SetWebKitSharedTimersSuspended(true));
65      suspended_processes_.push_back(host->GetID());
66    }
67  }
68
69  // Resumes timers in processes that were previously stopped.
70  void ResumeWebkitSharedTimers() {
71    for (std::vector<int>::const_iterator it = suspended_processes_.begin();
72         it != suspended_processes_.end(); ++it) {
73      content::RenderProcessHost* host =
74          content::RenderProcessHost::FromID(*it);
75      DCHECK(host);
76      host->RemoveObserver(this);
77      host->Send(new ViewMsg_SetWebKitSharedTimersSuspended(false));
78    }
79    suspended_processes_.clear();
80  }
81
82 private:
83  void StopWatching(content::RenderProcessHost* host) {
84    std::vector<int>::iterator pos = std::find(suspended_processes_.begin(),
85                                               suspended_processes_.end(),
86                                               host->GetID());
87    DCHECK_NE(pos, suspended_processes_.end());
88    host->RemoveObserver(this);
89    suspended_processes_.erase(pos);
90  }
91
92  std::vector<int /* RenderProcessHost id */> suspended_processes_;
93};
94
95base::LazyInstance<SuspendedProcessWatcher> g_suspended_processes_watcher =
96    LAZY_INSTANCE_INITIALIZER;
97
98}  // namespace
99
100// Returns the first substring consisting of the address of a physical location.
101static jstring FindAddress(JNIEnv* env, jclass clazz, jstring addr) {
102  base::string16 content_16 = ConvertJavaStringToUTF16(env, addr);
103  base::string16 result_16;
104  if (content::address_parser::FindAddress(content_16, &result_16))
105    return ConvertUTF16ToJavaString(env, result_16).Release();
106  return NULL;
107}
108
109static void SetWebKitSharedTimersSuspended(JNIEnv* env,
110                                           jclass obj,
111                                           jboolean suspend) {
112  if (suspend) {
113    g_suspended_processes_watcher.Pointer()->SuspendWebKitSharedTimers();
114  } else {
115    g_suspended_processes_watcher.Pointer()->ResumeWebkitSharedTimers();
116  }
117}
118
119namespace content {
120
121bool RegisterWebViewStatics(JNIEnv* env) {
122  return RegisterNativesImpl(env);
123}
124
125}  // namespace content
126