// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "client_handler.h" #include #include #include #include #include #include #include "browser_process_handler.h" #include "context_menu_handler.h" #include "dialog_handler.h" #include "display_handler.h" #include "download_handler.h" #include "drag_handler.h" #include "focus_handler.h" #include "jsdialog_handler.h" #include "keyboard_handler.h" #include "life_span_handler.h" #include "load_handler.h" #include "message_router_handler.h" #include "print_handler.h" #include "render_handler.h" #include "request_handler.h" #include "include/cef_browser.h" #include "include/cef_frame.h" #include "include/cef_parser.h" #include "include/cef_path_util.h" #include "include/cef_process_util.h" #include "include/cef_trace.h" #include "include/wrapper/cef_stream_resource_handler.h" #include "jni_util.h" #include "util.h" namespace { CefRefPtr GetMessageRouter(JNIEnv* env, jobject jmessageRouter) { ScopedJNIMessageRouter messageRouter(env); messageRouter.SetHandle(jmessageRouter, false /* should_delete */); return messageRouter.GetCefObject(); } CefMessageRouterConfig GetMessageRouterConfig(JNIEnv* env, jobject jmessageRouter) { ScopedJNIObjectResult jrouterConfig(env); JNI_CALL_METHOD(env, jmessageRouter, "getMessageRouterConfig", "()Lorg/cef/browser/CefMessageRouter$CefMessageRouterConfig;", Object, jrouterConfig); return GetJNIMessageRouterConfig(env, jrouterConfig); } } // namespace ClientHandler::ClientHandler(JNIEnv* env, jobject handler) : handle_(env, handler) {} template CefRefPtr ClientHandler::GetHandler(const char* class_name) { std::string methodName, className, methodSig; std::stringstream ss; ss << "get" << class_name; methodName = ss.str(); ss.str(std::string()); ss << "Cef" << class_name; className = ss.str(); ss.str(std::string()); ss << "()Lorg/cef/handler/" << className << ";"; methodSig = ss.str(); ScopedJNIEnv env; if (!env) return nullptr; CefRefPtr result = nullptr; ScopedJNIObjectResult jresult(env); JNI_CALL_METHOD(env, handle_, methodName.c_str(), methodSig.c_str(), Object, jresult); if (jresult) { ScopedJNIObject jhandler(env, jresult.Release(), true /* should_delete */, className.c_str()); result = jhandler.GetOrCreateCefObject(); } return result; } CefRefPtr ClientHandler::GetContextMenuHandler() { return GetHandler("ContextMenuHandler"); } CefRefPtr ClientHandler::GetDialogHandler() { return GetHandler("DialogHandler"); } CefRefPtr ClientHandler::GetDisplayHandler() { return GetHandler("DisplayHandler"); } CefRefPtr ClientHandler::GetDownloadHandler() { return GetHandler("DownloadHandler"); } CefRefPtr ClientHandler::GetDragHandler() { return GetHandler("DragHandler"); } CefRefPtr ClientHandler::GetFocusHandler() { return GetHandler("FocusHandler"); } CefRefPtr ClientHandler::GetJSDialogHandler() { return GetHandler("JSDialogHandler"); } CefRefPtr ClientHandler::GetKeyboardHandler() { return GetHandler("KeyboardHandler"); } CefRefPtr ClientHandler::GetLifeSpanHandler() { return GetHandler("LifeSpanHandler"); } CefRefPtr ClientHandler::GetLoadHandler() { return GetHandler("LoadHandler"); } CefRefPtr ClientHandler::GetPrintHandler() { return GetHandler("PrintHandler"); } CefRefPtr ClientHandler::GetRenderHandler() { return GetHandler("RenderHandler"); } CefRefPtr ClientHandler::GetRequestHandler() { return GetHandler("RequestHandler"); } bool ClientHandler::OnProcessMessageReceived( CefRefPtr browser, CefRefPtr frame, CefProcessId source_process, CefRefPtr message) { bool handled = false; // Iterate on a copy of |message_routers_| to avoid re-entrancy of // |message_router_lock_| if the client CefMessageRouterHandler impl // calls CefClientHandler.addMessageRouter/removeMessageRouter. MessageRouterSet message_routers; { base::AutoLock lock_scope(message_router_lock_); message_routers = message_routers_; } for (auto& router : message_routers) { handled = router->OnProcessMessageReceived(browser, frame, source_process, message); if (handled) break; } return handled; } CefRefPtr ClientHandler::GetWindowHandler() { return GetHandler("WindowHandler"); } void ClientHandler::AddMessageRouter(JNIEnv* env, jobject jmessageRouter) { CefRefPtr router = GetMessageRouter(env, jmessageRouter); if (!router) return; CefMessageRouterConfig config = GetMessageRouterConfig(env, jmessageRouter); // 1) Add CefMessageRouterBrowserSide into the list. { base::AutoLock lock_scope(message_router_lock_); message_routers_.insert(router); } // 2) Update CefApp for new render-processes. BrowserProcessHandler::AddMessageRouterConfig(config); // 3) Update running render-processes. BrowserSet allBrowsers = GetAllBrowsers(env); if (allBrowsers.empty()) return; CefRefPtr message = CefProcessMessage::Create("AddMessageRouter"); CefRefPtr args = message->GetArgumentList(); args->SetString(0, config.js_query_function); args->SetString(1, config.js_cancel_function); BrowserSet::const_iterator it = allBrowsers.begin(); for (; it != allBrowsers.end(); ++it) { (*it)->GetMainFrame()->SendProcessMessage(PID_RENDERER, message); } } void ClientHandler::RemoveMessageRouter(JNIEnv* env, jobject jmessageRouter) { CefRefPtr router = GetMessageRouter(env, jmessageRouter); if (!router) return; CefMessageRouterConfig config = GetMessageRouterConfig(env, jmessageRouter); // 1) Remove CefMessageRouterBrowserSide from the list. { base::AutoLock lock_scope(message_router_lock_); message_routers_.erase(router); } // 2) Update CefApp. BrowserProcessHandler::RemoveMessageRouterConfig(config); // 3) Update running render-processes. BrowserSet allBrowsers = GetAllBrowsers(env); if (allBrowsers.empty()) return; CefRefPtr message = CefProcessMessage::Create("RemoveMessageRouter"); CefRefPtr args = message->GetArgumentList(); args->SetString(0, config.js_query_function); args->SetString(1, config.js_cancel_function); BrowserSet::const_iterator it = allBrowsers.begin(); for (; it != allBrowsers.end(); ++it) { (*it)->GetMainFrame()->SendProcessMessage(PID_RENDERER, message); } } void ClientHandler::OnAfterCreated() {} void ClientHandler::OnBeforeClose(CefRefPtr browser) { REQUIRE_UI_THREAD(); base::AutoLock lock_scope(message_router_lock_); for (auto& router : message_routers_) { router->OnBeforeClose(browser); } } void ClientHandler::OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame) { REQUIRE_UI_THREAD(); base::AutoLock lock_scope(message_router_lock_); for (auto& router : message_routers_) { router->OnBeforeBrowse(browser, frame); } } void ClientHandler::OnRenderProcessTerminated(CefRefPtr browser) { REQUIRE_UI_THREAD(); base::AutoLock lock_scope(message_router_lock_); for (auto& router : message_routers_) { router->OnRenderProcessTerminated(browser); } } jobject ClientHandler::getBrowser(JNIEnv* env, CefRefPtr browser) { jobject jbrowser = nullptr; JNI_CALL_METHOD(env, handle_, "getBrowser", "(I)Lorg/cef/browser/CefBrowser;", Object, jbrowser, browser->GetIdentifier()); return jbrowser; } ClientHandler::BrowserSet ClientHandler::GetAllBrowsers(JNIEnv* env) { BrowserSet result; jobject jbrowsers = nullptr; JNI_CALL_METHOD(env, handle_, "getAllBrowser", "()[Ljava/lang/Object;", Object, jbrowsers); if (!jbrowsers) return result; jobjectArray jbrowserArray = (jobjectArray)jbrowsers; jint length = env->GetArrayLength(jbrowserArray); for (int i = 0; i < length; ++i) { jobject jbrowser = env->GetObjectArrayElement(jbrowserArray, i); if (!jbrowser) continue; ScopedJNIBrowser sbrowser(env); sbrowser.SetHandle(jbrowser, true /* should_delete */); CefRefPtr browser = sbrowser.GetCefObject(); if (!browser) continue; result.insert(browser); } env->DeleteLocalRef(jbrowserArray); return result; }