Bug 1975979 - Remove the crash helper listener socket on Linux and macOS a=dmeehan
Original Revision: https://phabricator.services.mozilla.com/D262410 Differential Revision: https://phabricator.services.mozilla.com/D263340
This commit is contained in:
committed by
dmeehan@mozilla.com
parent
d6674b563e
commit
a2e0149356
@@ -5,5 +5,5 @@
|
|||||||
package org.mozilla.gecko.crashhelper;
|
package org.mozilla.gecko.crashhelper;
|
||||||
|
|
||||||
interface ICrashHelper {
|
interface ICrashHelper {
|
||||||
boolean start(in int mainProcessPid, in ParcelFileDescriptor breakpadFd, in String minidumpPath, in ParcelFileDescriptor listenFd, in ParcelFileDescriptor serverFd);
|
boolean start(in ParcelFileDescriptor breakpadFd, in String minidumpPath, in ParcelFileDescriptor serverFd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import android.os.Binder;
|
|||||||
import android.os.DeadObjectException;
|
import android.os.DeadObjectException;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
@@ -43,10 +42,8 @@ public final class CrashHelper extends Service {
|
|||||||
private static class CrashHelperBinder extends ICrashHelper.Stub {
|
private static class CrashHelperBinder extends ICrashHelper.Stub {
|
||||||
@Override
|
@Override
|
||||||
public boolean start(
|
public boolean start(
|
||||||
final int clientPid,
|
|
||||||
final ParcelFileDescriptor breakpadFd,
|
final ParcelFileDescriptor breakpadFd,
|
||||||
final String minidumpPath,
|
final String minidumpPath,
|
||||||
final ParcelFileDescriptor listenFd,
|
|
||||||
final ParcelFileDescriptor serverFd) {
|
final ParcelFileDescriptor serverFd) {
|
||||||
// Launch the crash helper code, this will spin out a thread which will
|
// Launch the crash helper code, this will spin out a thread which will
|
||||||
// handle the IPC with Firefox' other processes. When running junit tests
|
// handle the IPC with Firefox' other processes. When running junit tests
|
||||||
@@ -56,8 +53,7 @@ public final class CrashHelper extends Service {
|
|||||||
// "steal" the crash report of another main process. We should add
|
// "steal" the crash report of another main process. We should add
|
||||||
// additional separation within the crash generation code to prevent this
|
// additional separation within the crash generation code to prevent this
|
||||||
// from happening even though it's very unlikely.
|
// from happening even though it's very unlikely.
|
||||||
CrashHelper.crash_generator(
|
CrashHelper.crash_generator(breakpadFd.detachFd(), minidumpPath, serverFd.detachFd());
|
||||||
clientPid, breakpadFd.detachFd(), minidumpPath, listenFd.detachFd(), serverFd.detachFd());
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -71,17 +67,14 @@ public final class CrashHelper extends Service {
|
|||||||
public static ServiceConnection createConnection(
|
public static ServiceConnection createConnection(
|
||||||
final ParcelFileDescriptor breakpadFd,
|
final ParcelFileDescriptor breakpadFd,
|
||||||
final String minidumpPath,
|
final String minidumpPath,
|
||||||
final ParcelFileDescriptor listenFd,
|
|
||||||
final ParcelFileDescriptor serverFd) {
|
final ParcelFileDescriptor serverFd) {
|
||||||
class CrashHelperConnection implements ServiceConnection {
|
class CrashHelperConnection implements ServiceConnection {
|
||||||
public CrashHelperConnection(
|
public CrashHelperConnection(
|
||||||
final ParcelFileDescriptor breakpadFd,
|
final ParcelFileDescriptor breakpadFd,
|
||||||
final String minidumpPath,
|
final String minidumpPath,
|
||||||
final ParcelFileDescriptor listenFd,
|
|
||||||
final ParcelFileDescriptor serverFd) {
|
final ParcelFileDescriptor serverFd) {
|
||||||
mBreakpadFd = breakpadFd;
|
mBreakpadFd = breakpadFd;
|
||||||
mMinidumpPath = minidumpPath;
|
mMinidumpPath = minidumpPath;
|
||||||
mListenFd = listenFd;
|
|
||||||
mServerFd = serverFd;
|
mServerFd = serverFd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +82,7 @@ public final class CrashHelper extends Service {
|
|||||||
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
public void onServiceConnected(final ComponentName name, final IBinder service) {
|
||||||
final ICrashHelper helper = ICrashHelper.Stub.asInterface(service);
|
final ICrashHelper helper = ICrashHelper.Stub.asInterface(service);
|
||||||
try {
|
try {
|
||||||
helper.start(Process.myPid(), mBreakpadFd, mMinidumpPath, mListenFd, mServerFd);
|
helper.start(mBreakpadFd, mMinidumpPath, mServerFd);
|
||||||
} catch (final DeadObjectException e) {
|
} catch (final DeadObjectException e) {
|
||||||
// The crash helper process died before we could start it, presumably
|
// The crash helper process died before we could start it, presumably
|
||||||
// because of an out-of-memory condition. We don't attempt to restart
|
// because of an out-of-memory condition. We don't attempt to restart
|
||||||
@@ -107,24 +100,21 @@ public final class CrashHelper extends Service {
|
|||||||
|
|
||||||
ParcelFileDescriptor mBreakpadFd;
|
ParcelFileDescriptor mBreakpadFd;
|
||||||
String mMinidumpPath;
|
String mMinidumpPath;
|
||||||
ParcelFileDescriptor mListenFd;
|
|
||||||
ParcelFileDescriptor mServerFd;
|
ParcelFileDescriptor mServerFd;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CrashHelperConnection(breakpadFd, minidumpPath, listenFd, serverFd);
|
return new CrashHelperConnection(breakpadFd, minidumpPath, serverFd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Pipes {
|
public static final class Pipes {
|
||||||
public final ParcelFileDescriptor mBreakpadClient;
|
public final ParcelFileDescriptor mBreakpadClient;
|
||||||
public final ParcelFileDescriptor mBreakpadServer;
|
public final ParcelFileDescriptor mBreakpadServer;
|
||||||
public final ParcelFileDescriptor mListener;
|
|
||||||
public final ParcelFileDescriptor mClient;
|
public final ParcelFileDescriptor mClient;
|
||||||
public final ParcelFileDescriptor mServer;
|
public final ParcelFileDescriptor mServer;
|
||||||
|
|
||||||
public Pipes(
|
public Pipes(
|
||||||
final FileDescriptor breakpadClientFd,
|
final FileDescriptor breakpadClientFd,
|
||||||
final FileDescriptor breakpadServerFd,
|
final FileDescriptor breakpadServerFd,
|
||||||
final FileDescriptor listenerFd,
|
|
||||||
final FileDescriptor clientFd,
|
final FileDescriptor clientFd,
|
||||||
final FileDescriptor serverFd)
|
final FileDescriptor serverFd)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
@@ -133,10 +123,6 @@ public final class CrashHelper extends Service {
|
|||||||
if (!CrashHelper.set_breakpad_opts(mBreakpadServer.getFd())) {
|
if (!CrashHelper.set_breakpad_opts(mBreakpadServer.getFd())) {
|
||||||
throw new IOException("Could not set the proper options on the Breakpad socket");
|
throw new IOException("Could not set the proper options on the Breakpad socket");
|
||||||
}
|
}
|
||||||
mListener = ParcelFileDescriptor.dup(listenerFd);
|
|
||||||
if (!CrashHelper.bind_and_listen(mListener.getFd())) {
|
|
||||||
throw new IOException("Could not listen on incoming connections");
|
|
||||||
}
|
|
||||||
mClient = ParcelFileDescriptor.dup(clientFd);
|
mClient = ParcelFileDescriptor.dup(clientFd);
|
||||||
mServer = ParcelFileDescriptor.dup(serverFd);
|
mServer = ParcelFileDescriptor.dup(serverFd);
|
||||||
}
|
}
|
||||||
@@ -151,8 +137,8 @@ public final class CrashHelper extends Service {
|
|||||||
public static Pipes createCrashHelperPipes(final Context context) {
|
public static Pipes createCrashHelperPipes(final Context context) {
|
||||||
try {
|
try {
|
||||||
// We can't set the required socket options for the Breakpad server socket
|
// We can't set the required socket options for the Breakpad server socket
|
||||||
// or our own listener from here, so we delegate those parts to native
|
// so we delegate those parts to native functions in
|
||||||
// functions in crashhelper_android.cpp.
|
// crashhelper_android.cpp.
|
||||||
GeckoLoader.doLoadLibrary(null, "crashhelper");
|
GeckoLoader.doLoadLibrary(null, "crashhelper");
|
||||||
|
|
||||||
final FileDescriptor breakpad_client_fd = new FileDescriptor();
|
final FileDescriptor breakpad_client_fd = new FileDescriptor();
|
||||||
@@ -163,14 +149,11 @@ public final class CrashHelper extends Service {
|
|||||||
0,
|
0,
|
||||||
breakpad_client_fd,
|
breakpad_client_fd,
|
||||||
breakpad_server_fd);
|
breakpad_server_fd);
|
||||||
final FileDescriptor listener_fd =
|
|
||||||
Os.socket(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0);
|
|
||||||
final FileDescriptor client_fd = new FileDescriptor();
|
final FileDescriptor client_fd = new FileDescriptor();
|
||||||
final FileDescriptor server_fd = new FileDescriptor();
|
final FileDescriptor server_fd = new FileDescriptor();
|
||||||
Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, client_fd, server_fd);
|
Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, client_fd, server_fd);
|
||||||
|
|
||||||
final Pipes pipes =
|
final Pipes pipes = new Pipes(breakpad_client_fd, breakpad_server_fd, client_fd, server_fd);
|
||||||
new Pipes(breakpad_client_fd, breakpad_server_fd, listener_fd, client_fd, server_fd);
|
|
||||||
|
|
||||||
// Manually close all the file descriptors we created.
|
// Manually close all the file descriptors we created.
|
||||||
// ParcelFileDescriptor instances in the Pipes object will close their
|
// ParcelFileDescriptor instances in the Pipes object will close their
|
||||||
@@ -178,7 +161,6 @@ public final class CrashHelper extends Service {
|
|||||||
// not, leaving us the job to clean them up.
|
// not, leaving us the job to clean them up.
|
||||||
Os.close(breakpad_client_fd);
|
Os.close(breakpad_client_fd);
|
||||||
Os.close(breakpad_server_fd);
|
Os.close(breakpad_server_fd);
|
||||||
Os.close(listener_fd);
|
|
||||||
Os.close(client_fd);
|
Os.close(client_fd);
|
||||||
Os.close(server_fd);
|
Os.close(server_fd);
|
||||||
return pipes;
|
return pipes;
|
||||||
@@ -192,10 +174,7 @@ public final class CrashHelper extends Service {
|
|||||||
// `stopWithTask` flag set in the manifest, so the service manager will
|
// `stopWithTask` flag set in the manifest, so the service manager will
|
||||||
// tear it down for us.
|
// tear it down for us.
|
||||||
|
|
||||||
protected static native void crash_generator(
|
protected static native void crash_generator(int breakpadFd, String minidumpPath, int serverFd);
|
||||||
int clientPid, int breakpadFd, String minidumpPath, int listenFd, int serverFd);
|
|
||||||
|
|
||||||
protected static native boolean set_breakpad_opts(int breakpadFd);
|
protected static native boolean set_breakpad_opts(int breakpadFd);
|
||||||
|
|
||||||
protected static native boolean bind_and_listen(int listenFd);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -459,8 +459,7 @@ public final class GeckoRuntime implements Parcelable {
|
|||||||
final File minidumps = new File(context.getFilesDir(), "minidumps");
|
final File minidumps = new File(context.getFilesDir(), "minidumps");
|
||||||
context.bindService(
|
context.bindService(
|
||||||
i,
|
i,
|
||||||
CrashHelper.createConnection(
|
CrashHelper.createConnection(pipes.mBreakpadServer, minidumps.getPath(), pipes.mServer),
|
||||||
pipes.mBreakpadServer, minidumps.getPath(), pipes.mListener, pipes.mServer),
|
|
||||||
Context.BIND_AUTO_CREATE);
|
Context.BIND_AUTO_CREATE);
|
||||||
} catch (final ClassNotFoundException e) {
|
} catch (final ClassNotFoundException e) {
|
||||||
Log.w(LOGTAG, "Couldn't find the crash helper class");
|
Log.w(LOGTAG, "Couldn't find the crash helper class");
|
||||||
|
|||||||
@@ -49,16 +49,31 @@ static void free_breakpad_data(BreakpadRawData aData) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GET_CLIENT_PID_ARG(arguments) ((arguments)[1])
|
||||||
|
#define GET_BREAKPAD_DATA_ARG(arguments) ((arguments)[2])
|
||||||
|
#define GET_MINIDUMP_PATH_ARG(arguments) ((arguments)[3])
|
||||||
|
#define GET_CONNECTOR_ARG(arguments) ((arguments)[4])
|
||||||
|
#ifdef XP_WIN
|
||||||
|
# define GET_LISTENER_ARG(arguments) ((arguments)[5])
|
||||||
|
# define ARG_NUM (6)
|
||||||
|
#else
|
||||||
|
static char sDummy[1] = "";
|
||||||
|
# define GET_LISTENER_ARG(arguments) (sDummy)
|
||||||
|
# define ARG_NUM (5)
|
||||||
|
#endif // XP_WIN
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc < 6) {
|
if (argc < ARG_NUM) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pid client_pid = static_cast<Pid>(parse_int_or_exit(argv[1]));
|
Pid client_pid =
|
||||||
BreakpadRawData breakpad_data = parse_breakpad_data(argv[2]);
|
static_cast<Pid>(parse_int_or_exit(GET_CLIENT_PID_ARG(argv)));
|
||||||
char* minidump_path = argv[3];
|
BreakpadRawData breakpad_data =
|
||||||
char* listener = argv[4];
|
parse_breakpad_data(GET_BREAKPAD_DATA_ARG(argv));
|
||||||
char* connector = argv[5];
|
char* minidump_path = GET_MINIDUMP_PATH_ARG(argv);
|
||||||
|
char* connector = GET_CONNECTOR_ARG(argv);
|
||||||
|
char* listener = GET_LISTENER_ARG(argv);
|
||||||
|
|
||||||
int res = crash_generator_logic_desktop(client_pid, breakpad_data,
|
int res = crash_generator_logic_desktop(client_pid, breakpad_data,
|
||||||
minidump_path, listener, connector);
|
minidump_path, listener, connector);
|
||||||
|
|||||||
@@ -30,36 +30,10 @@ Java_org_mozilla_gecko_crashhelper_CrashHelper_set_1breakpad_1opts(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jboolean JNICALL
|
|
||||||
Java_org_mozilla_gecko_crashhelper_CrashHelper_bind_1and_1listen(
|
|
||||||
JNIEnv* jenv, jclass, jint listen_fd) {
|
|
||||||
struct sockaddr_un addr = {
|
|
||||||
.sun_family = AF_UNIX,
|
|
||||||
.sun_path = {},
|
|
||||||
};
|
|
||||||
|
|
||||||
// The address' path deliberately starts with a null byte to inform the
|
|
||||||
// kernel that this is an abstract address and not an actual file path.
|
|
||||||
snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 2,
|
|
||||||
"gecko-crash-helper-pipe.%d", getpid());
|
|
||||||
|
|
||||||
int res = bind(listen_fd, (const struct sockaddr*)&addr, sizeof(addr));
|
|
||||||
if (res < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = listen(listen_fd, 1);
|
|
||||||
if (res < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_org_mozilla_gecko_crashhelper_CrashHelper_crash_1generator(
|
Java_org_mozilla_gecko_crashhelper_CrashHelper_crash_1generator(
|
||||||
JNIEnv* jenv, jclass, jint client_pid, jint breakpad_fd,
|
JNIEnv* jenv, jclass, jint breakpad_fd, jstring minidump_path,
|
||||||
jstring minidump_path, jint listen_fd, jint server_fd) {
|
jint server_fd) {
|
||||||
// The breakpad server socket needs to be put in non-blocking mode, we do it
|
// The breakpad server socket needs to be put in non-blocking mode, we do it
|
||||||
// here as the Rust code that picks it up won't touch it anymore and just
|
// here as the Rust code that picks it up won't touch it anymore and just
|
||||||
// pass it along to Breakpad.
|
// pass it along to Breakpad.
|
||||||
@@ -79,7 +53,6 @@ Java_org_mozilla_gecko_crashhelper_CrashHelper_crash_1generator(
|
|||||||
|
|
||||||
const char* minidump_path_str =
|
const char* minidump_path_str =
|
||||||
jenv->GetStringUTFChars(minidump_path, nullptr);
|
jenv->GetStringUTFChars(minidump_path, nullptr);
|
||||||
crash_generator_logic_android(client_pid, breakpad_fd, minidump_path_str,
|
crash_generator_logic_android(breakpad_fd, minidump_path_str, server_fd);
|
||||||
listen_fd, server_fd);
|
|
||||||
jenv->ReleaseStringUTFChars(minidump_path, minidump_path_str);
|
jenv->ReleaseStringUTFChars(minidump_path, minidump_path_str);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crash_helper_common::{
|
use crash_helper_common::{ignore_eintr, BreakpadChar, BreakpadData, IPCChannel, IPCConnector};
|
||||||
ignore_eintr, BreakpadChar, BreakpadData, IPCChannel, IPCConnector, IPCListener,
|
|
||||||
};
|
|
||||||
use nix::{
|
use nix::{
|
||||||
spawn::{posix_spawn, PosixSpawnAttr, PosixSpawnFileActions},
|
spawn::{posix_spawn, PosixSpawnAttr, PosixSpawnFileActions},
|
||||||
sys::wait::waitpid,
|
sys::wait::waitpid,
|
||||||
@@ -25,12 +23,11 @@ impl CrashHelperClient {
|
|||||||
minidump_path: *const BreakpadChar,
|
minidump_path: *const BreakpadChar,
|
||||||
) -> Result<CrashHelperClient> {
|
) -> Result<CrashHelperClient> {
|
||||||
let channel = IPCChannel::new()?;
|
let channel = IPCChannel::new()?;
|
||||||
let (listener, server_endpoint, client_endpoint) = channel.deconstruct();
|
let (_listener, server_endpoint, client_endpoint) = channel.deconstruct();
|
||||||
CrashHelperClient::spawn_crash_helper(
|
CrashHelperClient::spawn_crash_helper(
|
||||||
program,
|
program,
|
||||||
breakpad_data,
|
breakpad_data,
|
||||||
minidump_path,
|
minidump_path,
|
||||||
listener,
|
|
||||||
server_endpoint,
|
server_endpoint,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -45,7 +42,6 @@ impl CrashHelperClient {
|
|||||||
program: *const BreakpadChar,
|
program: *const BreakpadChar,
|
||||||
breakpad_data: BreakpadData,
|
breakpad_data: BreakpadData,
|
||||||
minidump_path: *const BreakpadChar,
|
minidump_path: *const BreakpadChar,
|
||||||
listener: IPCListener,
|
|
||||||
endpoint: IPCConnector,
|
endpoint: IPCConnector,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let parent_pid = getpid().to_string();
|
let parent_pid = getpid().to_string();
|
||||||
@@ -54,7 +50,6 @@ impl CrashHelperClient {
|
|||||||
let breakpad_data_arg =
|
let breakpad_data_arg =
|
||||||
unsafe { CString::from_vec_unchecked(breakpad_data.to_string().into_bytes()) };
|
unsafe { CString::from_vec_unchecked(breakpad_data.to_string().into_bytes()) };
|
||||||
let minidump_path = unsafe { CStr::from_ptr(minidump_path) };
|
let minidump_path = unsafe { CStr::from_ptr(minidump_path) };
|
||||||
let listener_arg = listener.serialize();
|
|
||||||
let endpoint_arg = endpoint.serialize();
|
let endpoint_arg = endpoint.serialize();
|
||||||
|
|
||||||
let file_actions = PosixSpawnFileActions::init()?;
|
let file_actions = PosixSpawnFileActions::init()?;
|
||||||
@@ -74,7 +69,6 @@ impl CrashHelperClient {
|
|||||||
&parent_pid_arg,
|
&parent_pid_arg,
|
||||||
&breakpad_data_arg,
|
&breakpad_data_arg,
|
||||||
minidump_path,
|
minidump_path,
|
||||||
&listener_arg,
|
|
||||||
&endpoint_arg,
|
&endpoint_arg,
|
||||||
],
|
],
|
||||||
env.as_slice(),
|
env.as_slice(),
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ impl CrashHelperClient {
|
|||||||
program,
|
program,
|
||||||
breakpad_data,
|
breakpad_data,
|
||||||
minidump_path,
|
minidump_path,
|
||||||
listener,
|
|
||||||
server_endpoint,
|
server_endpoint,
|
||||||
|
listener,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,8 +60,8 @@ impl CrashHelperClient {
|
|||||||
program: OsString,
|
program: OsString,
|
||||||
breakpad_data: BreakpadData,
|
breakpad_data: BreakpadData,
|
||||||
minidump_path: OsString,
|
minidump_path: OsString,
|
||||||
listener: IPCListener,
|
|
||||||
endpoint: IPCConnector,
|
endpoint: IPCConnector,
|
||||||
|
listener: IPCListener,
|
||||||
) -> Result<OwnedHandle> {
|
) -> Result<OwnedHandle> {
|
||||||
// SAFETY: `GetCurrentProcessId()` takes no arguments and should always work
|
// SAFETY: `GetCurrentProcessId()` takes no arguments and should always work
|
||||||
let pid = OsString::from(unsafe { GetCurrentProcessId() }.to_string());
|
let pid = OsString::from(unsafe { GetCurrentProcessId() }.to_string());
|
||||||
@@ -74,9 +74,9 @@ impl CrashHelperClient {
|
|||||||
cmd_line.push(" ");
|
cmd_line.push(" ");
|
||||||
cmd_line.push(escape_cmd_line_arg(&minidump_path));
|
cmd_line.push(escape_cmd_line_arg(&minidump_path));
|
||||||
cmd_line.push(" ");
|
cmd_line.push(" ");
|
||||||
cmd_line.push(escape_cmd_line_arg(&listener.serialize()));
|
|
||||||
cmd_line.push(" ");
|
|
||||||
cmd_line.push(escape_cmd_line_arg(&endpoint.serialize()));
|
cmd_line.push(escape_cmd_line_arg(&endpoint.serialize()));
|
||||||
|
cmd_line.push(" ");
|
||||||
|
cmd_line.push(escape_cmd_line_arg(&listener.serialize()));
|
||||||
cmd_line.push("\0");
|
cmd_line.push("\0");
|
||||||
let mut cmd_line: Vec<u16> = cmd_line.encode_wide().collect();
|
let mut cmd_line: Vec<u16> = cmd_line.encode_wide().collect();
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,19 @@
|
|||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||||
use crate::platform::linux::{
|
use crate::platform::linux::{
|
||||||
server_addr, set_socket_cloexec, set_socket_default_flags, unix_socket,
|
set_socket_cloexec, set_socket_default_flags,
|
||||||
};
|
};
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use crate::platform::macos::{
|
use crate::platform::macos::{
|
||||||
server_addr, set_socket_cloexec, set_socket_default_flags, unix_socket,
|
set_socket_cloexec, set_socket_default_flags,
|
||||||
};
|
};
|
||||||
use crate::{ignore_eintr, Pid, ProcessHandle, IO_TIMEOUT};
|
use crate::{ignore_eintr, ProcessHandle, IO_TIMEOUT};
|
||||||
|
|
||||||
use nix::{
|
use nix::{
|
||||||
cmsg_space,
|
cmsg_space,
|
||||||
errno::Errno,
|
errno::Errno,
|
||||||
poll::{poll, PollFd, PollFlags, PollTimeout},
|
poll::{poll, PollFd, PollFlags, PollTimeout},
|
||||||
sys::socket::{connect, recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags},
|
sys::socket::{recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
@@ -61,40 +61,6 @@ impl IPCConnector {
|
|||||||
IPCConnector::from_fd(unsafe { OwnedFd::from_raw_fd(ancillary_data) })
|
IPCConnector::from_fd(unsafe { OwnedFd::from_raw_fd(ancillary_data) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new connector by connecting it to the process specified by
|
|
||||||
/// `pid`. The `FD_CLOEXEC` flag will be set on the underlying socket and
|
|
||||||
/// thus it will not be possible to inerhit this connector in a child
|
|
||||||
/// process.
|
|
||||||
pub fn connect(pid: Pid) -> Result<IPCConnector, IPCError> {
|
|
||||||
let socket = unix_socket().map_err(IPCError::ConnectionFailure)?;
|
|
||||||
set_socket_default_flags(socket.as_fd()).map_err(IPCError::ConnectionFailure)?;
|
|
||||||
set_socket_cloexec(socket.as_fd()).map_err(IPCError::ConnectionFailure)?;
|
|
||||||
|
|
||||||
let server_addr = server_addr(pid).map_err(IPCError::ConnectionFailure)?;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let timeout = PollTimeout::from(IO_TIMEOUT);
|
|
||||||
let res = ignore_eintr!(poll(
|
|
||||||
&mut [PollFd::new(socket.as_fd(), PollFlags::POLLOUT)],
|
|
||||||
timeout
|
|
||||||
));
|
|
||||||
match res {
|
|
||||||
Err(e) => return Err(IPCError::ConnectionFailure(e)),
|
|
||||||
Ok(_res @ 0) => return Err(IPCError::ConnectionFailure(Errno::ETIMEDOUT)),
|
|
||||||
Ok(_) => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = ignore_eintr!(connect(socket.as_raw_fd(), &server_addr));
|
|
||||||
match res {
|
|
||||||
Ok(_) => break,
|
|
||||||
Err(_e @ Errno::EAGAIN) => continue, // Retry, the helper might not be ready yet
|
|
||||||
Err(e) => return Err(IPCError::ConnectionFailure(e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(IPCConnector { socket })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize this connector into a string that can be passed on the
|
/// Serialize this connector into a string that can be passed on the
|
||||||
/// command-line to a child process. This only works for newly
|
/// command-line to a child process. This only works for newly
|
||||||
/// created connectors because they are explicitly created as inheritable.
|
/// created connectors because they are explicitly created as inheritable.
|
||||||
@@ -131,7 +97,7 @@ impl IPCConnector {
|
|||||||
Ok(self.raw_fd())
|
Ok(self.raw_fd())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_raw_ref(&self) -> BorrowedFd {
|
pub fn as_raw_ref(&self) -> BorrowedFd<'_> {
|
||||||
self.socket.as_fd()
|
self.socket.as_fd()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,77 +2,24 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
use std::ffi::CStr;
|
||||||
use crate::platform::linux::{
|
|
||||||
server_addr, set_socket_cloexec, set_socket_default_flags, unix_socket,
|
|
||||||
};
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use crate::platform::macos::{
|
|
||||||
server_addr, set_socket_cloexec, set_socket_default_flags, unix_socket,
|
|
||||||
};
|
|
||||||
use crate::{errors::IPCError, IPCConnector, Pid};
|
|
||||||
|
|
||||||
use nix::sys::socket::{accept, bind, listen, Backlog};
|
use crate::{errors::IPCError, Pid};
|
||||||
use std::{
|
|
||||||
ffi::{CStr, CString},
|
|
||||||
os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct IPCListener {
|
pub struct IPCListener {}
|
||||||
socket: OwnedFd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IPCListener {
|
impl IPCListener {
|
||||||
/// Create a new listener with an address based on `pid`. The underlying
|
/// Create a new dummy listener. This is not used on Linux and macOS but
|
||||||
/// socket will not have the `FD_CLOEXEC` flag set and thus can be
|
/// we keep the type around so that the shared logic is the same as for
|
||||||
/// inherited by child processes.
|
/// Windows where this type is used.
|
||||||
pub fn new(pid: Pid) -> Result<IPCListener, IPCError> {
|
pub fn new(_pid: Pid) -> Result<IPCListener, IPCError> {
|
||||||
let socket = unix_socket().map_err(IPCError::System)?;
|
Ok(IPCListener {})
|
||||||
set_socket_default_flags(socket.as_fd()).map_err(IPCError::System)?;
|
|
||||||
|
|
||||||
let server_addr = server_addr(pid).map_err(IPCError::System)?;
|
|
||||||
bind(socket.as_fd().as_raw_fd(), &server_addr).map_err(IPCError::System)?;
|
|
||||||
listen(&socket, Backlog::new(1).unwrap()).map_err(IPCError::ListenFailed)?;
|
|
||||||
|
|
||||||
Ok(IPCListener { socket })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new listener using an already prepared socket. The listener
|
|
||||||
/// must have been bound to the appropriate address and should already be
|
|
||||||
/// listening on incoming connections. This will set the `FD_CLOEXEC` flag
|
|
||||||
/// on the underlying socket and thus will make this litener not inheritable
|
|
||||||
/// by child processes.
|
|
||||||
pub fn from_fd(_pid: Pid, socket: OwnedFd) -> Result<IPCListener, IPCError> {
|
|
||||||
set_socket_cloexec(socket.as_fd()).map_err(IPCError::System)?;
|
|
||||||
|
|
||||||
Ok(IPCListener { socket })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize this listener into a string that can be passed on the
|
|
||||||
/// command-line to a child process. This only works for newly
|
|
||||||
/// created listeners because they are explicitly created as inheritable.
|
|
||||||
pub fn serialize(&self) -> CString {
|
|
||||||
CString::new(self.socket.as_raw_fd().to_string()).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize a listener from an argument passed on the command-line.
|
/// Deserialize a listener from an argument passed on the command-line.
|
||||||
/// The resulting listener is ready to accept new connections.
|
/// This produces a dummy listener and is only kept to provide shared logic
|
||||||
pub fn deserialize(string: &CStr, _pid: Pid) -> Result<IPCListener, IPCError> {
|
/// with Windows.
|
||||||
let string = string.to_str().map_err(|_e| IPCError::ParseError)?;
|
pub fn deserialize(_string: &CStr, _pid: Pid) -> Result<IPCListener, IPCError> {
|
||||||
let fd = RawFd::from_str(string).map_err(|_e| IPCError::ParseError)?;
|
Ok(IPCListener {})
|
||||||
// SAFETY: This is a file descriptor we passed in ourselves.
|
|
||||||
let socket = unsafe { OwnedFd::from_raw_fd(fd) };
|
|
||||||
Ok(IPCListener { socket })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn accept(&self) -> Result<IPCConnector, IPCError> {
|
|
||||||
let socket = accept(self.socket.as_fd().as_raw_fd()).map_err(IPCError::AcceptFailed)?;
|
|
||||||
// SAFETY: `socket` is guaranteed to be valid at this point.
|
|
||||||
IPCConnector::from_fd(unsafe { OwnedFd::from_raw_fd(socket) })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_raw_ref(&self) -> BorrowedFd {
|
|
||||||
self.socket.as_fd()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ pub use crate::breakpad::{BreakpadChar, BreakpadData, BreakpadRawData, Pid};
|
|||||||
pub use crate::ipc_channel::{IPCChannel, IPCClientChannel};
|
pub use crate::ipc_channel::{IPCChannel, IPCClientChannel};
|
||||||
pub use crate::ipc_connector::{AncillaryData, IPCConnector, IPCEvent, INVALID_ANCILLARY_DATA};
|
pub use crate::ipc_connector::{AncillaryData, IPCConnector, IPCEvent, INVALID_ANCILLARY_DATA};
|
||||||
pub use crate::ipc_listener::IPCListener;
|
pub use crate::ipc_listener::IPCListener;
|
||||||
pub use crate::platform::{server_addr, ProcessHandle};
|
pub use crate::platform::ProcessHandle;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub use crate::platform::server_addr;
|
||||||
|
|
||||||
/// OsString extensions to convert from/to C strings. The strings will be
|
/// OsString extensions to convert from/to C strings. The strings will be
|
||||||
/// regular nul-terminated byte strings on most platforms but will use wide
|
/// regular nul-terminated byte strings on most platforms but will use wide
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ pub use windows::{server_addr, ProcessHandle};
|
|||||||
pub(crate) mod windows;
|
pub(crate) mod windows;
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||||
pub use linux::{server_addr, ProcessHandle};
|
pub use linux::ProcessHandle;
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||||
pub(crate) mod linux;
|
pub(crate) mod linux;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub use macos::{server_addr, ProcessHandle};
|
pub use macos::ProcessHandle;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub(crate) mod macos;
|
pub(crate) mod macos;
|
||||||
|
|||||||
@@ -2,33 +2,21 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::Pid;
|
|
||||||
|
|
||||||
use nix::{
|
use nix::{
|
||||||
fcntl::{
|
fcntl::{
|
||||||
fcntl,
|
fcntl,
|
||||||
FcntlArg::{F_GETFL, F_SETFD, F_SETFL},
|
FcntlArg::{F_GETFL, F_SETFD, F_SETFL},
|
||||||
FdFlag, OFlag,
|
FdFlag, OFlag,
|
||||||
},
|
},
|
||||||
sys::socket::{socket, socketpair, AddressFamily, SockFlag, SockType, UnixAddr},
|
sys::socket::{socketpair, AddressFamily, SockFlag, SockType},
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
|
||||||
os::fd::{BorrowedFd, OwnedFd},
|
os::fd::{BorrowedFd, OwnedFd},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ProcessHandle = ();
|
pub type ProcessHandle = ();
|
||||||
|
|
||||||
pub(crate) fn unix_socket() -> Result<OwnedFd> {
|
|
||||||
socket(
|
|
||||||
AddressFamily::Unix,
|
|
||||||
SockType::SeqPacket,
|
|
||||||
SockFlag::empty(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unix_socketpair() -> Result<(OwnedFd, OwnedFd)> {
|
pub(crate) fn unix_socketpair() -> Result<(OwnedFd, OwnedFd)> {
|
||||||
socketpair(
|
socketpair(
|
||||||
AddressFamily::Unix,
|
AddressFamily::Unix,
|
||||||
@@ -47,12 +35,3 @@ pub(crate) fn set_socket_default_flags(socket: BorrowedFd) -> Result<()> {
|
|||||||
pub(crate) fn set_socket_cloexec(socket: BorrowedFd) -> Result<()> {
|
pub(crate) fn set_socket_cloexec(socket: BorrowedFd) -> Result<()> {
|
||||||
fcntl(socket, F_SETFD(FdFlag::FD_CLOEXEC)).map(|_res| ())
|
fcntl(socket, F_SETFD(FdFlag::FD_CLOEXEC)).map(|_res| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn server_addr(pid: Pid) -> Result<UnixAddr> {
|
|
||||||
let server_name = if let Ok(snap_instance_name) = env::var("SNAP_INSTANCE_NAME") {
|
|
||||||
format!("snap.{snap_instance_name:}.gecko-crash-helper-pipe.{pid:}")
|
|
||||||
} else {
|
|
||||||
format!("gecko-crash-helper-pipe.{pid:}")
|
|
||||||
};
|
|
||||||
UnixAddr::new_abstract(server_name.as_bytes())
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::Pid;
|
|
||||||
|
|
||||||
use nix::{
|
use nix::{
|
||||||
errno::Errno,
|
errno::Errno,
|
||||||
fcntl::{
|
fcntl::{
|
||||||
@@ -12,27 +10,16 @@ use nix::{
|
|||||||
FdFlag, OFlag,
|
FdFlag, OFlag,
|
||||||
},
|
},
|
||||||
libc::{setsockopt, SOL_SOCKET, SO_NOSIGPIPE},
|
libc::{setsockopt, SOL_SOCKET, SO_NOSIGPIPE},
|
||||||
sys::socket::{socket, socketpair, AddressFamily, SockFlag, SockType, UnixAddr},
|
sys::socket::{socketpair, AddressFamily, SockFlag, SockType},
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
mem::size_of,
|
mem::size_of,
|
||||||
os::fd::{AsRawFd, BorrowedFd, OwnedFd},
|
os::fd::{AsRawFd, BorrowedFd, OwnedFd},
|
||||||
path::PathBuf,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ProcessHandle = ();
|
pub type ProcessHandle = ();
|
||||||
|
|
||||||
pub(crate) fn unix_socket() -> Result<OwnedFd> {
|
|
||||||
socket(
|
|
||||||
AddressFamily::Unix,
|
|
||||||
SockType::Stream,
|
|
||||||
SockFlag::empty(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unix_socketpair() -> Result<(OwnedFd, OwnedFd)> {
|
pub(crate) fn unix_socketpair() -> Result<(OwnedFd, OwnedFd)> {
|
||||||
socketpair(
|
socketpair(
|
||||||
AddressFamily::Unix,
|
AddressFamily::Unix,
|
||||||
@@ -70,11 +57,3 @@ pub(crate) fn set_socket_default_flags(socket: BorrowedFd) -> Result<()> {
|
|||||||
pub(crate) fn set_socket_cloexec(socket: BorrowedFd) -> Result<()> {
|
pub(crate) fn set_socket_cloexec(socket: BorrowedFd) -> Result<()> {
|
||||||
fcntl(socket, F_SETFD(FdFlag::FD_CLOEXEC)).map(|_res| ())
|
fcntl(socket, F_SETFD(FdFlag::FD_CLOEXEC)).map(|_res| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn server_addr(pid: Pid) -> Result<UnixAddr> {
|
|
||||||
// macOS doesn't seem to support abstract paths as addresses for Unix
|
|
||||||
// protocol sockets, so this needs to be the path of an actual file.
|
|
||||||
let server_name = format!("/tmp/gecko-crash-helper-pipe.{pid:}");
|
|
||||||
let server_path = PathBuf::from_str(&server_name).unwrap();
|
|
||||||
UnixAddr::new(&server_path)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ struct IPCConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct IPCServer {
|
pub(crate) struct IPCServer {
|
||||||
|
#[cfg_attr(unix, allow(dead_code))]
|
||||||
listener: IPCListener,
|
listener: IPCListener,
|
||||||
connections: Vec<IPCConnection>,
|
connections: Vec<IPCConnection>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,13 @@
|
|||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crash_helper_common::{errors::IPCError, ignore_eintr, IPCEvent};
|
use crash_helper_common::{errors::IPCError, ignore_eintr, IPCEvent};
|
||||||
use nix::{
|
use nix::poll::{poll, PollFd, PollFlags, PollTimeout};
|
||||||
errno::Errno,
|
|
||||||
poll::{poll, PollFd, PollFlags, PollTimeout},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::IPCServer;
|
use super::IPCServer;
|
||||||
|
|
||||||
impl IPCServer {
|
impl IPCServer {
|
||||||
pub fn wait_for_events(&mut self) -> Result<Vec<IPCEvent>, IPCError> {
|
pub fn wait_for_events(&mut self) -> Result<Vec<IPCEvent>, IPCError> {
|
||||||
let mut pollfds = Vec::with_capacity(1 + self.connections.len());
|
let mut pollfds = Vec::with_capacity(self.connections.len());
|
||||||
pollfds.push(PollFd::new(self.listener.as_raw_ref(), PollFlags::POLLIN));
|
|
||||||
pollfds.extend(
|
pollfds.extend(
|
||||||
self.connections.iter().map(|connection| {
|
self.connections.iter().map(|connection| {
|
||||||
PollFd::new(connection.connector.as_raw_ref(), PollFlags::POLLIN)
|
PollFd::new(connection.connector.as_raw_ref(), PollFlags::POLLIN)
|
||||||
@@ -31,39 +27,27 @@ impl IPCServer {
|
|||||||
let revents = pollfd.revents().unwrap();
|
let revents = pollfd.revents().unwrap();
|
||||||
|
|
||||||
if revents.contains(PollFlags::POLLHUP) {
|
if revents.contains(PollFlags::POLLHUP) {
|
||||||
if index > 0 {
|
events.push(IPCEvent::Disconnect(index));
|
||||||
events.push(IPCEvent::Disconnect(index - 1));
|
// If a process was disconnected then skip all further
|
||||||
// If a process was disconnected then skip all further
|
// processing of the socket. This wouldn't matter normally,
|
||||||
// processing of the socket. This wouldn't matter normally,
|
// but on macOS calling recvmsg() on a hung-up socket seems
|
||||||
// but on macOS calling recvmsg() on a hung-up socket seems
|
// to trigger a kernel panic, one we've already encountered
|
||||||
// to trigger a kernel panic, one we've already encountered
|
// in the past. Doing things this way avoids the panic
|
||||||
// in the past. Doing things this way avoids the panic
|
// while having no real downsides.
|
||||||
// while having no real downsides.
|
continue;
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// This should never happen, unless the listener socket was
|
|
||||||
// not set up properly or a failure happened during setup.
|
|
||||||
return Err(IPCError::System(Errno::EFAULT));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if revents.contains(PollFlags::POLLIN) {
|
if revents.contains(PollFlags::POLLIN) {
|
||||||
if index == 0 {
|
// SAFETY: The index is guaranteed to be >0 and within
|
||||||
if let Ok(connector) = self.listener.accept() {
|
// the bounds of the connections array.
|
||||||
events.push(IPCEvent::Connect(connector));
|
let connection = unsafe { self.connections.get_unchecked(index) };
|
||||||
}
|
let header = connection.connector.recv_header();
|
||||||
} else {
|
if let Ok(header) = header {
|
||||||
// SAFETY: The index is guaranteed to be >0 and within
|
// Note that if we encounter a failure we don't propagate
|
||||||
// the bounds of the connections array.
|
// it, when the socket gets disconnected we'll get a
|
||||||
let connection = unsafe { self.connections.get_unchecked(index - 1) };
|
// POLLHUP event anyway so deal with disconnections there
|
||||||
let header = connection.connector.recv_header();
|
// instead of here.
|
||||||
if let Ok(header) = header {
|
events.push(IPCEvent::Header(index, header));
|
||||||
// Note that if we encounter a failure we don't propagate
|
|
||||||
// it, when the socket gets disconnected we'll get a
|
|
||||||
// POLLHUP event anyway so deal with disconnections there
|
|
||||||
// instead of here.
|
|
||||||
events.push(IPCEvent::Header(index - 1, header));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ mod ipc_server;
|
|||||||
mod logging;
|
mod logging;
|
||||||
mod phc;
|
mod phc;
|
||||||
|
|
||||||
use crash_helper_common::{BreakpadData, BreakpadRawData, IPCConnector, IPCListener, Pid};
|
#[cfg(not(target_os = "android"))]
|
||||||
|
use crash_helper_common::Pid;
|
||||||
|
use crash_helper_common::{BreakpadData, BreakpadRawData, IPCConnector, IPCListener};
|
||||||
use std::ffi::{c_char, CStr, OsString};
|
use std::ffi::{c_char, CStr, OsString};
|
||||||
|
|
||||||
use crash_generation::CrashGenerator;
|
use crash_generation::CrashGenerator;
|
||||||
@@ -82,17 +84,14 @@ pub unsafe extern "C" fn crash_generator_logic_desktop(
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `minidump_data` must point to valid, nul-terminated C strings. `listener`
|
/// `minidump_data` must point to valid, nul-terminated C strings. `server_pipe`
|
||||||
/// and `server_pipe` must be valid file descriptors and `breakpad_data` must
|
/// must be a valid file descriptor and `breakpad_data` must also be a valid
|
||||||
/// also be a valid file descriptor compatible with Breakpad's crash generation
|
/// file descriptor compatible with Breakpad's crash generation server.
|
||||||
/// server.
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn crash_generator_logic_android(
|
pub unsafe extern "C" fn crash_generator_logic_android(
|
||||||
client_pid: Pid,
|
|
||||||
breakpad_data: BreakpadRawData,
|
breakpad_data: BreakpadRawData,
|
||||||
minidump_path: *const c_char,
|
minidump_path: *const c_char,
|
||||||
listener: RawFd,
|
|
||||||
pipe: RawFd,
|
pipe: RawFd,
|
||||||
) {
|
) {
|
||||||
logging::init();
|
logging::init();
|
||||||
@@ -110,12 +109,7 @@ pub unsafe extern "C" fn crash_generator_logic_android(
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let listener = unsafe { OwnedFd::from_raw_fd(listener) };
|
let listener = IPCListener::new(0).unwrap();
|
||||||
let listener = IPCListener::from_fd(client_pid, listener)
|
|
||||||
.map_err(|error| {
|
|
||||||
log::error!("Could not use the listener (error: {error})");
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
let pipe = unsafe { OwnedFd::from_raw_fd(pipe) };
|
let pipe = unsafe { OwnedFd::from_raw_fd(pipe) };
|
||||||
let connector = IPCConnector::from_fd(pipe)
|
let connector = IPCConnector::from_fd(pipe)
|
||||||
.map_err(|error| {
|
.map_err(|error| {
|
||||||
|
|||||||
Reference in New Issue
Block a user