Page 2 of 2

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Tue Jun 15, 2021 4:45 am
by amaitland
You don't need to attach type=renderer, chromium will launch the sub processes with the appropriate command line args.

Sandbox is optional.

I cannot say if your main entry point is correct as the example you provided is incomplete.

You can set the log path via CefSettings.

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Tue Jun 15, 2021 6:00 am
by michaelb
Okay, so I reran the program with the log file enabled and redirected to a known path, and the
Code: Select all
--renderer-startup-dialog --no-sandbox
command line arguments, where I got the behavior of the multiple popups for the render process pid. About 2-4 in the beginning of each run. I attached all of them to the VS debugger. This time they didn't keep on popping back up again. However, my app's RenderProcessHandler's event callback methods did not get hit (after browser created, I attached the processes to debugger, then there was a sleep for a few minutes, then the browser was closed, and my breakpoint in OnBrowserDestroyed in my app did not get hit). There was nothing special or errors in the logs, however we do see that the render process(es) are running.

At this point I am very stuck. What else could it be?

This is the entire main entry point:
Code: Select all
    CEFManager(int port)
    {
        char pathStr[MAX_PATH];
#ifdef _WIN32
        ::GetModuleFileName(NULL, pathStr, MAX_PATH);
#else
        auto pathStrLen = readlink("/proc/self/exe", pathStr, MAX_PATH);
        pathStr[pathStrLen] = '\0'; // readlink returns non-null-terminating strings, so terminate.
#endif

#ifndef _WIN64
        char** args = new char*[1];
        args[0] = pathStr;
        CefMainArgs mainArgs(1, args);
#else
        CefMainArgs mainArgs(GetModuleHandle(NULL));
#endif
        CefRefPtr<RendererApp> app = new RendererApp();

        int exit_code = CefExecuteProcess(mainArgs, app.get(), nullptr);

        CefSettings settings;

        std::string path = pathStr;
        auto loc = path.find_last_of('/');
        if (loc == std::string::npos)
        {
            loc = path.find_last_of('\\');
        }
        auto const WORKER_PATH = path.substr(0, loc + 1) +
#ifndef _WIN64
            "CEFWorker";
#else
            "CEFWorker.exe";
#endif
        if (!boost::filesystem::exists(WORKER_PATH))
        {
            Logger::getInstance().logMessage(Severity::FATAL_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__, "CEF Worker executable not found at %s", WORKER_PATH.c_str());
        }
        CefString(&settings.browser_subprocess_path).FromASCII(WORKER_PATH.c_str());
        settings.no_sandbox = true;
        settings.log_severity = LOGSEVERITY_VERBOSE;
        CefString(&settings.log_file) = path.substr(0, loc + 1) + "cef_debug.log";
        settings.windowless_rendering_enabled = true;
        settings.multi_threaded_message_loop = true;
        settings.remote_debugging_port = port;
        Logger::getInstance().logMessage(Severity::INFO_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__, "HeadlessBrowser Runnig on Port %d", port);

        // If not in Windows, take locales and resources from PATH
#ifndef _WIN64
        const std::string RESOURCES_DIR_PATH = "/opt/cef/resources";
        CefString(&settings.resources_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());
        CefString(&settings.locales_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());

        Logger::getInstance().logMessage(Severity::INFO_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__,
            "CEF Headless browser looking for resources in %s", RESOURCES_DIR_PATH.c_str());
#else
        bool success = false;
        const std::string RESOURCES_DIR_PATH = Utils::getVenueInstalledDirectory() + "\\Bin";
        CefString(&settings.resources_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());
        CefString(&settings.locales_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());

        Logger::getInstance().logMessage(Severity::INFO_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__,
            "CEF Headless browser looking for resources in %s", RESOURCES_DIR_PATH.c_str());
#endif

        // Initialize CEF.
        _initializedCorrectly = CefInitialize(mainArgs, settings, app, nullptr);
    }

    bool _initializedCorrectly = false;
};

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Tue Jun 15, 2021 2:35 pm
by amaitland
You don't appear to be handling the CefExecuteProcess call correctly, you need to exit the process if it returns greater than -1.

Is your main application CEFWorker.exe? Or are you using a separate executable for the sub process?

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Wed Jun 16, 2021 1:46 am
by michaelb
It's returning -1, but it's supposed to be the render process not the browser process. It might be something we need to fix but I am not sure that is the issue causing the render process not to hit our overriden callback methods.
I think there are separate CEFWorker.exes, when we run our program I see 4-5 CEFWorker.exes in the task manager.

The render processes start up much later in our code on browser creation, but these are not the render processes we want that redirect to our overridden callback code... this CefExecuteProcess call is what we want to be the render process, and then upon browser startup, using this render process with our callback functions.

Or is the browser creation supposed to start render processes that automatically redirect to our callback functions in our app that extends CefApp & CefRenderHandler, but then what would be the point of doing CefExecuteProcess on the render process, which returns -1 anyways?

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Wed Jun 16, 2021 2:15 am
by amaitland
Or is the browser creation supposed to start render processes that automatically redirect to our callback functions in our app that extends CefApp & CefRenderHandler, but then what would be the point of doing CefExecuteProcess on the render process, which returns -1 anyways?


You seem to have gotten rather confused about how the process model works. You don't call CefExecuteProcess to spawn a render process. The fact that it's returning -1 means you are in the browser process (your main application). Chromium will spawn multiple instances of your application or a separate executable to host the sub processes.

You need to add your render handler code to CEFWorker.exe.

Is there someone in your dev team who did the initial implementation? Be really useful if there was someone you could ask for guidance in person.

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Wed Jun 16, 2021 2:45 am
by michaelb
So, CefExecuteProcess doesn't spawn a new process?
Yes, I am in the main application entry point... so it's good that it's returning -1?

Our render handler code is inside "RendererApp", which we are passing into CefExecuteProcess and CefInitialize ... isn't this how to attach it to CEFWorker.exe (the exe name in the main entry point)? Or is something missing?

Yes, there were other people who did the initial implementation, I am new and inherited that code, not sure if the other people are still around or available but I could look into that. In any case, the code I shared is our entire application entry point, so it all should be in there. There was no CefExecuteProcess - that is me attempting to add that in order to hit our RenderProcessHandler javascript binding code. I will reshare the code here for convenience.

Code: Select all
    CEFManager(int port)
    {
        char pathStr[MAX_PATH];
#ifdef _WIN32
        ::GetModuleFileName(NULL, pathStr, MAX_PATH);
#else
        auto pathStrLen = readlink("/proc/self/exe", pathStr, MAX_PATH);
        pathStr[pathStrLen] = '\0'; // readlink returns non-null-terminating strings, so terminate.
#endif

#ifndef _WIN64
        char** args = new char*[1];
        args[0] = pathStr;
        CefMainArgs mainArgs(1, args);
#else
        CefMainArgs mainArgs(GetModuleHandle(NULL));
#endif
        CefRefPtr<RendererApp> app = new RendererApp();

        int exit_code = CefExecuteProcess(mainArgs, app.get(), nullptr);

        CefSettings settings;

        std::string path = pathStr;
        auto loc = path.find_last_of('/');
        if (loc == std::string::npos)
        {
            loc = path.find_last_of('\\');
        }
        auto const WORKER_PATH = path.substr(0, loc + 1) +
#ifndef _WIN64
            "CEFWorker";
#else
            "CEFWorker.exe";
#endif
        if (!boost::filesystem::exists(WORKER_PATH))
        {
            Logger::getInstance().logMessage(Severity::FATAL_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__, "CEF Worker executable not found at %s", WORKER_PATH.c_str());
        }
        CefString(&settings.browser_subprocess_path).FromASCII(WORKER_PATH.c_str());
        settings.no_sandbox = true;
        settings.log_severity = LOGSEVERITY_VERBOSE;
        CefString(&settings.log_file) = path.substr(0, loc + 1) + "cef_debug.log";
        settings.windowless_rendering_enabled = true;
        settings.multi_threaded_message_loop = true;
        settings.remote_debugging_port = port;
        Logger::getInstance().logMessage(Severity::INFO_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__, "HeadlessBrowser Runnig on Port %d", port);

        // If not in Windows, take locales and resources from PATH
#ifndef _WIN64
        const std::string RESOURCES_DIR_PATH = "/opt/cef/resources";
        CefString(&settings.resources_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());
        CefString(&settings.locales_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());

        Logger::getInstance().logMessage(Severity::INFO_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__,
            "CEF Headless browser looking for resources in %s", RESOURCES_DIR_PATH.c_str());
#else
        bool success = false;
        const std::string RESOURCES_DIR_PATH = Utils::getVenueInstalledDirectory() + "\\Bin";
        CefString(&settings.resources_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());
        CefString(&settings.locales_dir_path).FromASCII(RESOURCES_DIR_PATH.c_str());

        Logger::getInstance().logMessage(Severity::INFO_LEVEL, "CEF", __FUNCTION__, __FILE__, __LINE__,
            "CEF Headless browser looking for resources in %s", RESOURCES_DIR_PATH.c_str());
#endif

        // Initialize CEF.
        _initializedCorrectly = CefInitialize(mainArgs, settings, app, nullptr);
    }

    bool _initializedCorrectly = false;
};

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Wed Jun 16, 2021 4:27 am
by amaitland
So, CefExecuteProcess doesn't spawn a new process?


That's correct.

Yes, I am in the main application entry point... so it's good that it's returning -1?


That's expected. Basically means it recognised your are in the main application and does nothing. It would block until completion otherwise.

There was no CefExecuteProcess - that is me attempting to add that in order to hit our RenderProcessHandler javascript binding code. I will reshare the code here for convenience.


The sub process won't run without `CefExecuteProcess ` and based on the browser_subprocess_path it's very likely that you are using a separate exe for the sub process.

My guess is that CEFWorker.exe is an entirely different application. You need to find the source for `CEFWorker.exe`

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Wed Jun 16, 2021 4:53 am
by michaelb
So we don't have any source code for CefWorker.exe
Just the main application entry point code, which references this as the browser sub-process path.
Could this in and of itself be the issue, that we need to implement the sub-process entry point? And since we didn't, the "CefWorker.exes" that run are just some default/empty ones? Something has to be running them though as they appear in task manager and we are checking for their existence in the main application entry point, yet we don't have any source code for it...

Re: CEF RenderProcessHandler's callback methods not being hi

PostPosted: Wed Jun 16, 2021 5:22 am
by michaelb
Update: I found the source code for our CefWorker.exe
I will look into it. thanks