private void finishBuild(Throwable error, boolean hadBuildErrors, boolean markedUptodateFiles) {
    CmdlineRemoteProto.Message lastMessage = null;
    try {
      if (error != null) {
        Throwable cause = error.getCause();
        if (cause == null) {
          cause = error;
        }
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final PrintStream stream = new PrintStream(out);
        try {
          cause.printStackTrace(stream);
        } finally {
          stream.close();
        }

        final StringBuilder messageText = new StringBuilder();
        messageText
            .append("Internal error: (")
            .append(cause.getClass().getName())
            .append(") ")
            .append(cause.getMessage());
        final String trace = out.toString();
        if (!trace.isEmpty()) {
          messageText.append("\n").append(trace);
        }
        lastMessage =
            CmdlineProtoUtil.toMessage(
                mySessionId, CmdlineProtoUtil.createFailure(messageText.toString(), cause));
      } else {
        CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status status =
            CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.SUCCESS;
        if (myCanceled) {
          status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.CANCELED;
        } else if (hadBuildErrors) {
          status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.ERRORS;
        } else if (!markedUptodateFiles) {
          status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.UP_TO_DATE;
        }
        lastMessage =
            CmdlineProtoUtil.toMessage(
                mySessionId, CmdlineProtoUtil.createBuildCompletedEvent("build completed", status));
      }
    } catch (Throwable e) {
      lastMessage =
          CmdlineProtoUtil.toMessage(
              mySessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
    } finally {
      try {
        Channels.write(myChannel, lastMessage).await();
      } catch (InterruptedException e) {
        LOG.info(e);
      }
    }
  }
 @Nullable
 @Override
 public Future<Callbacks.ConstantAffection> request(
     String ownerClassName,
     String fieldName,
     int accessFlags,
     boolean fieldRemoved,
     boolean accessChanged) {
   final CmdlineRemoteProto.Message.BuilderMessage.ConstantSearchTask.Builder task =
       CmdlineRemoteProto.Message.BuilderMessage.ConstantSearchTask.newBuilder();
   task.setOwnerClassName(ownerClassName);
   task.setFieldName(fieldName);
   task.setAccessFlags(accessFlags);
   task.setIsAccessChanged(accessChanged);
   task.setIsFieldRemoved(fieldRemoved);
   final ConstantSearchFuture future = new ConstantSearchFuture(BuildSession.this);
   final ConstantSearchFuture prev =
       mySearchTasks.put(new Pair<String, String>(ownerClassName, fieldName), future);
   if (prev != null) {
     prev.setDone();
   }
   Channels.write(
       myChannel,
       CmdlineProtoUtil.toMessage(
           mySessionId,
           CmdlineRemoteProto.Message.BuilderMessage.newBuilder()
               .setType(CmdlineRemoteProto.Message.BuilderMessage.Type.CONSTANT_SEARCH_TASK)
               .setConstantSearchTask(task.build())
               .build()));
   return future;
 }