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 21 using base::android::ConvertJavaStringToUTF16; 22 using base::android::ConvertUTF16ToJavaString; 23 24 namespace { 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. 38 class 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 95 base::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. 101 static 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 109 static 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 119 namespace content { 120 121 bool RegisterWebViewStatics(JNIEnv* env) { 122 return RegisterNativesImpl(env); 123 } 124 125 } // namespace content 126