check_child_pid_status (void *user_data)
{
  /* Stores a sequence of the time interval to use until the child PID is checked again.
     In general from testing, bwrapinfo is never ready before 25ms have passed at minimum,
     thus 25ms is the first interval, doubling until a max interval of 100ms is reached.

     In addition, if the program is not available after 100ms for an extended period of time,
     the timeout is further increased to a full second. */
  static gint timeouts[] = {25, 50, 100};

  g_autoptr(GVariant) signal_variant = NULL;
  g_autoptr(BwrapinfoWatcherData) data = user_data;
  PidData *pid_data;
  guint pid;
  int child_pid;
  int relative_child_pid = 0;

  pid = data->pid;

  pid_data = g_hash_table_lookup (client_pid_data_hash, GUINT_TO_POINTER (pid));

  /* Process likely already exited if pid_data == NULL, so don't send the
     signal to avoid an awkward out-of-order SpawnExited -> SpawnStarted. */
  if (pid_data == NULL)
    {
      g_warning ("%u already exited, skipping SpawnStarted", pid);
      return G_SOURCE_REMOVE;
    }

  child_pid = flatpak_instance_get_child_pid (data->instance);
  if (child_pid == 0)
    {
      gint timeout;
      gboolean readd_timer = FALSE;

      if (data->attempt >= CHILD_STATUS_CHECK_ATTEMPTS)
        /* If too many attempts, use a 1 second timeout */
        timeout = 1000;
      else
        timeout = timeouts[MIN (data->attempt, G_N_ELEMENTS (timeouts) - 1)];

      g_debug ("Failed to read child PID, trying again in %d ms", timeout);

      /* The timer source only needs to be re-added if the timeout has changed,
          which won't happen while staying on the 100 or 1000ms timeouts.

          This test must happen *before* the attempt counter is incremented, since the
          attempt counter represents the *current* timeout. */
      readd_timer = data->attempt <= G_N_ELEMENTS (timeouts) || data->attempt == CHILD_STATUS_CHECK_ATTEMPTS;
      data->attempt++;

      /* Make sure the data isn't destroyed */
      data = NULL;

      if (readd_timer)
        {
          g_timeout_add (timeout, check_child_pid_status, user_data);
          return G_SOURCE_REMOVE;
        }

      return G_SOURCE_CONTINUE;
    }

  /* Only send the child PID if it's exposed */
  if (pid_data->expose_or_share_pids)
    {
      g_autoptr(GError) error = NULL;
      relative_child_pid = get_child_pid_relative_to_parent_sandbox (child_pid, &error);
      if (relative_child_pid == 0)
        g_warning ("Failed to find relative PID for %d: %s", child_pid, error->message);
    }

  g_debug ("Emitting SpawnStarted(%u, %d)", pid, relative_child_pid);

  signal_variant = g_variant_ref_sink (g_variant_new ("(uu)", pid, relative_child_pid));
  g_dbus_connection_emit_signal (session_bus,
                                 pid_data->client,
                                 "/org/freedesktop/portal/Flatpak",
                                 "org.freedesktop.portal.Flatpak",
                                 "SpawnStarted",
                                 signal_variant,
                                 NULL);

  return G_SOURCE_REMOVE;
}
check_child_pid_status (void *user_data)
{
   
  static gint timeouts[] = {25, 50, 100};

  g_autoptr(GVariant) signal_variant = NULL;
  g_autoptr(BwrapinfoWatcherData) data = user_data;
  PidData *pid_data;
  guint pid;
  int child_pid;
  int relative_child_pid = 0;

  pid = data->pid;

  pid_data = g_hash_table_lookup (client_pid_data_hash, GUINT_TO_POINTER (pid));

   
  if (pid_data == NULL)
    {
      g_warning ("%u already exited, skipping SpawnStarted", pid);
      return G_SOURCE_REMOVE;
    }

  child_pid = flatpak_instance_get_child_pid (data->instance);
  if (child_pid == 0)
    {
      gint timeout;
      gboolean readd_timer = FALSE;

      if (data->attempt >= CHILD_STATUS_CHECK_ATTEMPTS)
         
        timeout = 1000;
      else
        timeout = timeouts[MIN (data->attempt, G_N_ELEMENTS (timeouts) - 1)];

      g_debug ("Failed to read child PID, trying again in %d ms", timeout);

       
      readd_timer = data->attempt <= G_N_ELEMENTS (timeouts) || data->attempt == CHILD_STATUS_CHECK_ATTEMPTS;
      data->attempt++;

       
      data = NULL;

      if (readd_timer)
        {
          g_timeout_add (timeout, check_child_pid_status, user_data);
          return G_SOURCE_REMOVE;
        }

      return G_SOURCE_CONTINUE;
    }

   
  if (pid_data->expose_or_share_pids)
    {
      g_autoptr(GError) error = NULL;
      relative_child_pid = get_child_pid_relative_to_parent_sandbox (child_pid, &error);
      if (relative_child_pid == 0)
        g_warning ("Failed to find relative PID for %d: %s", child_pid, error->message);
    }

  g_debug ("Emitting SpawnStarted(%u, %d)", pid, relative_child_pid);

  signal_variant = g_variant_ref_sink (g_variant_new ("(uu)", pid, relative_child_pid));
  g_dbus_connection_emit_signal (session_bus,
                                 pid_data->client,
                                 "/org/freedesktop/portal/Flatpak",
                                 "org.freedesktop.portal.Flatpak",
                                 "SpawnStarted",
                                 signal_variant,
                                 NULL);

  return G_SOURCE_REMOVE;
}