docs: public void setChannel(@Nonnull Channel channel,
                             @CheckForNull OutputStream launchLog,
                             @CheckForNull Channel.Listener listener) throws IOException, InterruptedException {
          if(this.channel!=null)
              throw new IllegalStateException("Already connected");
  
          final TaskListener taskListener = launchLog != null ? new StreamTaskListener(launchLog) : TaskListener.NULL;
          PrintStream log = taskListener.getLogger();
  
          channel.setProperty(SlaveComputer.class, this);
  
          channel.addListener(new LoggingChannelListener(logger, Level.FINEST) {
              @Override
              public void onClosed(Channel c, IOException cause) {
                  // Orderly shutdown will have null exception
                  if (cause!=null) {
                      offlineCause = new ChannelTermination(cause);
                      Functions.printStackTrace(cause, taskListener.error("Connection terminated"));
                  } else {
                      taskListener.getLogger().println("Connection terminated");
                  }
                  closeChannel();
                  try {
                      launcher.afterDisconnect(SlaveComputer.this, taskListener);
                  } catch (Throwable t) {
                      LogRecord lr = new LogRecord(Level.SEVERE,
                              "Launcher {0}'s afterDisconnect method propagated an exception when {1}'s connection was closed: {2}");
                      lr.setThrown(t);
                      lr.setParameters(new Object[]{launcher, SlaveComputer.this.getName(), t.getMessage()});
                      logger.log(lr);
                  }
              }
          });
          if(listener!=null)
              channel.addListener(listener);
  
          String slaveVersion = channel.call(new SlaveVersion());
          log.println("Remoting version: " + slaveVersion);
          VersionNumber agentVersion = new VersionNumber(slaveVersion);
          if (agentVersion.isOlderThan(RemotingVersionInfo.getMinimumSupportedVersion())) {
              log.println(String.format("WARNING: Remoting version is older than a minimum required one (%s). " +
                      "Connection will not be rejected, but the compatibility is NOT guaranteed",
                      RemotingVersionInfo.getMinimumSupportedVersion()));
          }
  
          boolean _isUnix = channel.call(new DetectOS());
          log.println(_isUnix? hudson.model.Messages.Slave_UnixSlave():hudson.model.Messages.Slave_WindowsSlave());
  
          String defaultCharsetName = channel.call(new DetectDefaultCharset());
  
          Slave node = getNode();
          if (node == null) { // Node has been disabled/removed during the connection
              throw new IOException("Node "+nodeName+" has been deleted during the channel setup");
          }
  
          String remoteFS = node.getRemoteFS();
          if (Util.isRelativePath(remoteFS)) {
              remoteFS = channel.call(new AbsolutePath(remoteFS));
              log.println("NOTE: Relative remote path resolved to: "+remoteFS);
          }
          if(_isUnix && !remoteFS.contains("/") && remoteFS.contains("\\"))
              log.println("WARNING: "+remoteFS
                      +" looks suspiciously like Windows path. Maybe you meant "+remoteFS.replace('\\','/')+"?");
          FilePath root = new FilePath(channel,remoteFS);
  
          // reference counting problem is known to happen, such as JENKINS-9017, and so as a preventive measure
          // we pin the base classloader so that it'll never get GCed. When this classloader gets released,
          // it'll have a catastrophic impact on the communication.
          channel.pinClassLoader(getClass().getClassLoader());
  
          channel.call(new SlaveInitializer(DEFAULT_RING_BUFFER_SIZE));
          SecurityContext old = ACL.impersonate(ACL.SYSTEM);
          try {
              for (ComputerListener cl : ComputerListener.all()) {
                  cl.preOnline(this,channel,root,taskListener);
              }
          } finally {
              SecurityContextHolder.setContext(old);
          }
  
          offlineCause = null;
  
          // update the data structure atomically to prevent others from seeing a channel that's not properly initialized yet
          synchronized(channelLock) {
              if(this.channel!=null) {
                  // check again. we used to have this entire method in a big synchronization block,
                  // but Channel constructor blocks for an external process to do the connection
                  // if CommandLauncher is used, and that cannot be interrupted because it blocks at InputStream.
                  // so if the process hangs, it hangs the thread in a lock, and since Hudson will try to relaunch,
                  // we'll end up queuing the lot of threads in a pseudo deadlock.
                  // This implementation prevents that by avoiding a lock. HUDSON-1705 is likely a manifestation of this.
                  channel.close();
                  throw new IllegalStateException("Already connected");
              }
              isUnix = _isUnix;
              numRetryAttempt = 0;
              this.channel = channel;
              this.absoluteRemoteFs = remoteFS;
              defaultCharset = Charset.forName(defaultCharsetName);
  
              synchronized (statusChangeLock) {
                  statusChangeLock.notifyAll();
              }
          }
          old = ACL.impersonate(ACL.SYSTEM);
          try {
              for (ComputerListener cl : ComputerListener.all()) {
                  cl.onOnline(this,taskListener);
              }
          } finally {
              SecurityContextHolder.setContext(old);
          }
          log.println("Agent successfully connected and online");
          Jenkins.get().getQueue().scheduleMaintenance();
      }