def _TimeoutRetryWrapper(f, timeout_func, retries_func, pass_values=False):
  """ Wraps a funcion with timeout and retry handling logic.

  Args:
    f: The function to wrap.
    timeout_func: A callable that returns the timeout value.
    retries_func: A callable that returns the retries value.
    pass_values: If True, passes the values returned by |timeout_func| and
                 |retries_func| to the wrapped function as 'timeout' and
                 'retries' kwargs, respectively.
  Returns:
    The wrapped function.
  """
  @functools.wraps(f)
  def timeout_retry_wrapper(*args, **kwargs):
    timeout = timeout_func(*args, **kwargs)
    retries = retries_func(*args, **kwargs)
    if pass_values:
      kwargs['timeout'] = timeout
      kwargs['retries'] = retries
    @functools.wraps(f)
    def impl():
      return f(*args, **kwargs)
    try:
      if timeout_retry.CurrentTimeoutThreadGroup():
        # Don't wrap if there's already an outer timeout thread.
        return impl()
      else:
        desc = '%s(%s)' % (f.__name__, ', '.join(itertools.chain(
            (str(a) for a in args),
            ('%s=%s' % (k, str(v)) for k, v in kwargs.iteritems()))))
        return timeout_retry.Run(impl, timeout, retries, desc=desc)
    except reraiser_thread.TimeoutError as e:
      raise device_errors.CommandTimeoutError(str(e)), None, (
          sys.exc_info()[2])
    except cmd_helper.TimeoutError as e:
      raise device_errors.CommandTimeoutError(str(e)), None, (
          sys.exc_info()[2])
  return timeout_retry_wrapper