• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20262

05 May 2026 04:08PM UTC coverage: 88.807% (-0.002%) from 88.809%
#20262

push

github

ejona86
Upgrading Build Environment to Ubuntu 24.04
1. Transition to Ubuntu 24.04
Ubuntu 18.04 has reached End-of-Life (EOL), making standard package repositories unreliable. More critically, legacy versions like 18.04 and 20.04 lack modern root SSL certificates required to securely communicate with internal build infrastructure, leading to handshake failures. Moving to Ubuntu 24.04 provides a modern baseline with updated certificate stores that trust required mirrors out-of-the-box.

2. Mandatory Use of Internal Mirrors
The Kokoro grpc-ubuntu22 worker pool operates under strict egress restrictions that block connections to public Ubuntu archives (e.g., archive.ubuntu.com), resulting in Connection failed errors. To bypass this firewall, we must redirect apt traffic to the internal Google mirror (mirror.bazel.build) using a sed command in the Dockerfile.

3. Bumping JDK to Version 11
Ubuntu 24.04 no longer includes the ancient openjdk-8-jdk in its default repositories. To ensure compatibility with the new OS and maintain a supportable toolchain, we have bumped the version to openjdk-11-jdk.

4. Transition from pkg-config to pkgconf
Following modern Debian/Ubuntu packaging standards, we have replaced pkg-config with pkgconf which is the preferred, actively maintained implementation for package discovery in newer Ubuntu releases.

36140 of 40695 relevant lines covered (88.81%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.05
/../okhttp/src/main/java/io/grpc/okhttp/ExceptionHandlingFrameWriter.java
1
/*
2
 * Copyright 2018 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.okhttp;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.common.annotations.VisibleForTesting;
22
import com.google.common.base.Preconditions;
23
import io.grpc.okhttp.internal.framed.ErrorCode;
24
import io.grpc.okhttp.internal.framed.FrameWriter;
25
import io.grpc.okhttp.internal.framed.Header;
26
import io.grpc.okhttp.internal.framed.Settings;
27
import java.io.IOException;
28
import java.util.List;
29
import java.util.logging.Level;
30
import java.util.logging.Logger;
31
import okio.Buffer;
32
import okio.ByteString;
33

34
/**
35
 * FrameWriter that propagates IOExceptions via callback instead of throwing. This allows
36
 * centralized handling of errors. Exceptions only impact the single call that throws them; callers
37
 * should be sure to kill the connection after an exception (potentially after sending a GOAWAY) as
38
 * otherwise additional frames after the failed/omitted one could cause HTTP/2 confusion.
39
 */
40
final class ExceptionHandlingFrameWriter implements FrameWriter {
41

42
  private static final Logger log = Logger.getLogger(OkHttpClientTransport.class.getName());
1✔
43

44
  private final TransportExceptionHandler transportExceptionHandler;
45

46
  private final FrameWriter frameWriter;
47

48
  private final OkHttpFrameLogger frameLogger =
1✔
49
      new OkHttpFrameLogger(Level.FINE, OkHttpClientTransport.class);
50

51
  ExceptionHandlingFrameWriter(
52
      TransportExceptionHandler transportExceptionHandler, FrameWriter frameWriter) {
1✔
53
    this.transportExceptionHandler =
1✔
54
        checkNotNull(transportExceptionHandler, "transportExceptionHandler");
1✔
55
    this.frameWriter = Preconditions.checkNotNull(frameWriter, "frameWriter");
1✔
56
  }
1✔
57

58
  @Override
59
  public void connectionPreface() {
60
    try {
61
      frameWriter.connectionPreface();
1✔
62
    } catch (IOException e) {
×
63
      transportExceptionHandler.onException(e);
×
64
    }
1✔
65
  }
1✔
66

67
  @Override
68
  public void ackSettings(Settings peerSettings) {
69
    frameLogger.logSettingsAck(OkHttpFrameLogger.Direction.OUTBOUND);
1✔
70
    try {
71
      frameWriter.ackSettings(peerSettings);
1✔
72
    } catch (IOException e) {
1✔
73
      transportExceptionHandler.onException(e);
1✔
74
    }
1✔
75
  }
1✔
76

77
  @Override
78
  public void pushPromise(int streamId, int promisedStreamId, List<Header> requestHeaders) {
79
    frameLogger.logPushPromise(OkHttpFrameLogger.Direction.OUTBOUND,
1✔
80
        streamId, promisedStreamId, requestHeaders);
81
    try {
82
      frameWriter.pushPromise(streamId, promisedStreamId, requestHeaders);
1✔
83
    } catch (IOException e) {
×
84
      transportExceptionHandler.onException(e);
×
85
    }
1✔
86
  }
1✔
87

88
  @Override
89
  public void flush() {
90
    try {
91
      frameWriter.flush();
1✔
92
    } catch (IOException e) {
1✔
93
      transportExceptionHandler.onException(e);
1✔
94
    }
1✔
95
  }
1✔
96

97
  @Override
98
  public void synStream(
99
      boolean outFinished,
100
      boolean inFinished,
101
      int streamId,
102
      int associatedStreamId,
103
      List<Header> headerBlock) {
104
    try {
105
      frameWriter.synStream(outFinished, inFinished, streamId, associatedStreamId, headerBlock);
1✔
106
    } catch (IOException e) {
×
107
      transportExceptionHandler.onException(e);
×
108
    }
1✔
109
  }
1✔
110

111
  @Override
112
  public void synReply(boolean outFinished, int streamId,
113
      List<Header> headerBlock) {
114
    try {
115
      frameWriter.synReply(outFinished, streamId, headerBlock);
1✔
116
    } catch (IOException e) {
1✔
117
      transportExceptionHandler.onException(e);
1✔
118
    }
1✔
119
  }
1✔
120

121
  @Override
122
  public void headers(int streamId, List<Header> headerBlock) {
123
    frameLogger.logHeaders(OkHttpFrameLogger.Direction.OUTBOUND, streamId, headerBlock, false);
1✔
124
    try {
125
      frameWriter.headers(streamId, headerBlock);
1✔
126
    } catch (IOException e) {
×
127
      transportExceptionHandler.onException(e);
×
128
    }
1✔
129
  }
1✔
130

131
  @Override
132
  public void rstStream(int streamId, ErrorCode errorCode) {
133
    frameLogger.logRstStream(OkHttpFrameLogger.Direction.OUTBOUND, streamId, errorCode);
1✔
134
    try {
135
      frameWriter.rstStream(streamId, errorCode);
1✔
136
    } catch (IOException e) {
1✔
137
      transportExceptionHandler.onException(e);
1✔
138
    }
1✔
139
  }
1✔
140

141
  @Override
142
  public int maxDataLength() {
143
    return frameWriter.maxDataLength();
1✔
144
  }
145

146
  @Override
147
  public void data(boolean outFinished, int streamId, Buffer source, int byteCount) {
148
    frameLogger.logData(OkHttpFrameLogger.Direction.OUTBOUND,
1✔
149
        streamId, source.buffer(), byteCount, outFinished);
1✔
150
    try {
151
      frameWriter.data(outFinished, streamId, source, byteCount);
1✔
152
    } catch (IOException e) {
×
153
      transportExceptionHandler.onException(e);
×
154
    }
1✔
155
  }
1✔
156

157
  @Override
158
  public void settings(Settings okHttpSettings) {
159
    frameLogger.logSettings(OkHttpFrameLogger.Direction.OUTBOUND, okHttpSettings);
1✔
160
    try {
161
      frameWriter.settings(okHttpSettings);
1✔
162
    } catch (IOException e) {
×
163
      transportExceptionHandler.onException(e);
×
164
    }
1✔
165
  }
1✔
166

167
  @Override
168
  public void ping(boolean ack, int payload1, int payload2) {
169
    if (ack) {
1✔
170
      frameLogger.logPingAck(OkHttpFrameLogger.Direction.OUTBOUND,
1✔
171
          ((long) payload1 << 32) | (payload2 & 0xFFFFFFFFL));
172
    } else {
173
      frameLogger.logPing(OkHttpFrameLogger.Direction.OUTBOUND,
1✔
174
          ((long) payload1 << 32) | (payload2 & 0xFFFFFFFFL));
175
    }
176
    try {
177
      frameWriter.ping(ack, payload1, payload2);
1✔
178
    } catch (IOException e) {
×
179
      transportExceptionHandler.onException(e);
×
180
    }
1✔
181
  }
1✔
182

183
  @Override
184
  public void goAway(int lastGoodStreamId, ErrorCode errorCode,
185
      byte[] debugData) {
186
    frameLogger.logGoAway(OkHttpFrameLogger.Direction.OUTBOUND,
1✔
187
        lastGoodStreamId, errorCode, ByteString.of(debugData));
1✔
188
    try {
189
      frameWriter.goAway(lastGoodStreamId, errorCode, debugData);
1✔
190
      // Flush it since after goAway, we are likely to close this writer.
191
      frameWriter.flush();
1✔
192
    } catch (IOException e) {
1✔
193
      transportExceptionHandler.onException(e);
1✔
194
    }
1✔
195
  }
1✔
196

197
  @Override
198
  public void windowUpdate(int streamId, long windowSizeIncrement) {
199
    frameLogger.logWindowsUpdate(OkHttpFrameLogger.Direction.OUTBOUND,
1✔
200
        streamId, windowSizeIncrement);
201
    try {
202
      frameWriter.windowUpdate(streamId, windowSizeIncrement);
1✔
203
    } catch (IOException e) {
×
204
      transportExceptionHandler.onException(e);
×
205
    }
1✔
206
  }
1✔
207

208
  @Override
209
  public void close() {
210
    try {
211
      frameWriter.close();
1✔
212
    } catch (IOException e) {
×
213
      log.log(getLogLevel(e), "Failed closing connection", e);
×
214
    }
1✔
215
  }
1✔
216

217
  /**
218
   * Accepts a throwable and returns the appropriate logging level. Uninteresting exceptions
219
   * should not clutter the log.
220
   */
221
  @VisibleForTesting
222
  static Level getLogLevel(Throwable t) {
223
    if (t.getClass().equals(IOException.class)) {
1✔
224
      return Level.FINE;
1✔
225
    }
226
    return Level.INFO;
1✔
227
  }
228

229
  /** A class that handles transport exception. */
230
  interface TransportExceptionHandler {
231
    /** Handles exception. */
232
    void onException(Throwable throwable);
233
  }
234
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc