Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: components/cronet/android/java/src/org/chromium/net/CronetUploadDataStream.java

Issue 1849753002: [Cronet] Separate Cronet implementation and API by package name. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: sync Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.net;
6
7 import android.util.Log;
8
9 import org.chromium.base.VisibleForTesting;
10 import org.chromium.base.annotations.CalledByNative;
11 import org.chromium.base.annotations.JNINamespace;
12 import org.chromium.base.annotations.NativeClassQualifiedName;
13
14 import java.io.IOException;
15 import java.nio.ByteBuffer;
16 import java.util.concurrent.Executor;
17
18 import javax.annotation.concurrent.GuardedBy;
19
20 /**
21 * CronetUploadDataStream handles communication between an upload body
22 * encapsulated in the embedder's {@link UploadDataSink} and a C++
23 * UploadDataStreamAdapter, which it owns. It's attached to a {@link
24 * CronetUrlRequest}'s during the construction of request's native C++ objects
25 * on the network thread, though it's created on one of the embedder's threads.
26 * It is called by the UploadDataStreamAdapter on the network thread, but calls
27 * into the UploadDataSink and the UploadDataStreamAdapter on the Executor
28 * passed into its constructor.
29 */
30 @JNINamespace("cronet")
31 final class CronetUploadDataStream implements UploadDataSink {
32 private static final String TAG = "CronetUploadDataStream";
33 // These are never changed, once a request starts.
34 private final Executor mExecutor;
35 private final UploadDataProvider mDataProvider;
36 private long mLength;
37 private long mRemainingLength;
38 private CronetUrlRequest mRequest;
39
40 // Reusable read task, to reduce redundant memory allocation.
41 private final Runnable mReadTask = new Runnable() {
42 @Override
43 public void run() {
44 synchronized (mLock) {
45 if (mUploadDataStreamAdapter == 0) {
46 return;
47 }
48 checkState(UserCallback.NOT_IN_CALLBACK);
49 if (mByteBuffer == null) {
50 throw new IllegalStateException(
51 "Unexpected readData call. Buffer is null");
52 }
53 mInWhichUserCallback = UserCallback.READ;
54 }
55 try {
56 mDataProvider.read(CronetUploadDataStream.this, mByteBuffer);
57 } catch (Exception exception) {
58 onError(exception);
59 }
60 }
61 };
62
63 // ByteBuffer created in the native code and passed to
64 // UploadDataProvider for reading. It is only valid from the
65 // call to mDataProvider.read until onError or onReadSucceeded.
66 private ByteBuffer mByteBuffer = null;
67
68 // Lock that protects all subsequent variables. The adapter has to be
69 // protected to ensure safe shutdown, mReading and mRewinding are protected
70 // to robustly detect getting read/rewind results more often than expected.
71 private final Object mLock = new Object();
72
73 // Native adapter object, owned by the CronetUploadDataStream. It's only
74 // deleted after the native UploadDataStream object is destroyed. All access
75 // to the adapter is synchronized, for safe usage and cleanup.
76 @GuardedBy("mLock")
77 private long mUploadDataStreamAdapter = 0;
78 enum UserCallback {
79 READ,
80 REWIND,
81 GET_LENGTH,
82 NOT_IN_CALLBACK,
83 }
84 @GuardedBy("mLock")
85 private UserCallback mInWhichUserCallback = UserCallback.NOT_IN_CALLBACK;
86 @GuardedBy("mLock")
87 private boolean mDestroyAdapterPostponed = false;
88 private Runnable mOnDestroyedCallbackForTesting;
89
90 /**
91 * Constructs a CronetUploadDataStream.
92 * @param dataProvider the UploadDataProvider to read data from.
93 * @param executor the Executor to execute UploadDataProvider tasks.
94 */
95 public CronetUploadDataStream(UploadDataProvider dataProvider, Executor exec utor) {
96 mExecutor = executor;
97 mDataProvider = dataProvider;
98 }
99
100 /**
101 * Called by native code to make the UploadDataProvider read data into
102 * {@code byteBuffer}.
103 */
104 @SuppressWarnings("unused")
105 @CalledByNative
106 void readData(ByteBuffer byteBuffer) {
107 mByteBuffer = byteBuffer;
108 postTaskToExecutor(mReadTask);
109 }
110
111 // TODO(mmenke): Consider implementing a cancel method.
112 // currently wait for any pending read to complete.
113
114 /**
115 * Called by native code to make the UploadDataProvider rewind upload data.
116 */
117 @SuppressWarnings("unused")
118 @CalledByNative
119 void rewind() {
120 Runnable task = new Runnable() {
121 @Override
122 public void run() {
123 synchronized (mLock) {
124 if (mUploadDataStreamAdapter == 0) {
125 return;
126 }
127 checkState(UserCallback.NOT_IN_CALLBACK);
128 mInWhichUserCallback = UserCallback.REWIND;
129 }
130 try {
131 mDataProvider.rewind(CronetUploadDataStream.this);
132 } catch (Exception exception) {
133 onError(exception);
134 }
135 }
136 };
137 postTaskToExecutor(task);
138 }
139
140 @GuardedBy("mLock")
141 private void checkState(UserCallback mode) {
142 if (mInWhichUserCallback != mode) {
143 throw new IllegalStateException(
144 "Expected " + mode + ", but was " + mInWhichUserCallback);
145 }
146 }
147
148 /**
149 * Called when the native UploadDataStream is destroyed. At this point,
150 * the native adapter needs to be destroyed, but only after any pending
151 * read operation completes, as the adapter owns the read buffer.
152 */
153 @SuppressWarnings("unused")
154 @CalledByNative
155 void onUploadDataStreamDestroyed() {
156 destroyAdapter();
157 }
158
159 /**
160 * Helper method called when an exception occurred. This method resets
161 * states and propagates the error to the request.
162 */
163 private void onError(Throwable exception) {
164 synchronized (mLock) {
165 if (mInWhichUserCallback == UserCallback.NOT_IN_CALLBACK) {
166 throw new IllegalStateException(
167 "There is no read or rewind or length check in progress. ");
168 }
169 mInWhichUserCallback = UserCallback.NOT_IN_CALLBACK;
170 mByteBuffer = null;
171 destroyAdapterIfPostponed();
172 }
173
174 // Just fail the request - simpler to fail directly, and
175 // UploadDataStream only supports failing during initialization, not
176 // while reading. The request is smart enough to handle the case where
177 // it was already canceled by the embedder.
178 mRequest.onUploadException(exception);
179 }
180
181 @Override
182 public void onReadSucceeded(boolean lastChunk) {
183 synchronized (mLock) {
184 checkState(UserCallback.READ);
185 if (lastChunk && mLength >= 0) {
186 throw new IllegalArgumentException(
187 "Non-chunked upload can't have last chunk");
188 }
189 int bytesRead = mByteBuffer.position();
190 mRemainingLength -= bytesRead;
191 if (mRemainingLength < 0 && mLength >= 0) {
192 throw new IllegalArgumentException(
193 String.format("Read upload data length %d exceeds expect ed length %d",
194 mLength - mRemainingLength, mLength));
195 }
196 mByteBuffer = null;
197 mInWhichUserCallback = UserCallback.NOT_IN_CALLBACK;
198
199 destroyAdapterIfPostponed();
200 // Request may been canceled already.
201 if (mUploadDataStreamAdapter == 0) {
202 return;
203 }
204 nativeOnReadSucceeded(mUploadDataStreamAdapter, bytesRead,
205 lastChunk);
206 }
207 }
208
209 @Override
210 public void onReadError(Exception exception) {
211 synchronized (mLock) {
212 checkState(UserCallback.READ);
213 onError(exception);
214 }
215 }
216
217 @Override
218 public void onRewindSucceeded() {
219 synchronized (mLock) {
220 checkState(UserCallback.REWIND);
221 mInWhichUserCallback = UserCallback.NOT_IN_CALLBACK;
222 mRemainingLength = mLength;
223 // Request may been canceled already.
224 if (mUploadDataStreamAdapter == 0) {
225 return;
226 }
227 nativeOnRewindSucceeded(mUploadDataStreamAdapter);
228 }
229 }
230
231 @Override
232 public void onRewindError(Exception exception) {
233 synchronized (mLock) {
234 checkState(UserCallback.REWIND);
235 onError(exception);
236 }
237 }
238
239 /**
240 * Posts task to application Executor.
241 */
242 void postTaskToExecutor(Runnable task) {
243 try {
244 mExecutor.execute(task);
245 } catch (Throwable e) {
246 // Just fail the request. The request is smart enough to handle the
247 // case where it was already canceled by the embedder.
248 mRequest.onUploadException(e);
249 }
250 }
251
252 /**
253 * The adapter is owned by the CronetUploadDataStream, so it can be
254 * destroyed safely when there is no pending read; however, destruction is
255 * initiated by the destruction of the native UploadDataStream.
256 */
257 private void destroyAdapter() {
258 synchronized (mLock) {
259 if (mInWhichUserCallback == UserCallback.READ) {
260 // Wait for the read to complete before destroy the adapter.
261 mDestroyAdapterPostponed = true;
262 return;
263 }
264 if (mUploadDataStreamAdapter == 0) {
265 return;
266 }
267 nativeDestroy(mUploadDataStreamAdapter);
268 mUploadDataStreamAdapter = 0;
269 if (mOnDestroyedCallbackForTesting != null) {
270 mOnDestroyedCallbackForTesting.run();
271 }
272 }
273 postTaskToExecutor(new Runnable() {
274 @Override
275 public void run() {
276 try {
277 mDataProvider.close();
278 } catch (IOException e) {
279 Log.e(TAG, "Exception thrown when closing", e);
280 }
281 }
282 });
283 }
284
285 /**
286 * Destroys the native adapter if the destruction is postponed due to a
287 * pending read, which has since completed. Caller needs to be on executor
288 * thread.
289 */
290 private void destroyAdapterIfPostponed() {
291 synchronized (mLock) {
292 if (mInWhichUserCallback == UserCallback.READ) {
293 throw new IllegalStateException(
294 "Method should not be called when read has not completed .");
295 }
296 if (mDestroyAdapterPostponed) {
297 destroyAdapter();
298 }
299 }
300 }
301
302 /**
303 * Initializes upload length by getting it from data provider. Always called
304 * on executor thread to allow getLength() to block and/or report errors.
305 * If data provider throws an exception, then it is reported to the request.
306 * No native calls to urlRequest are allowed as this is done before request
307 * start, so native object may not exist.
308 */
309 void initializeWithRequest(final CronetUrlRequest urlRequest) {
310 synchronized (mLock) {
311 mRequest = urlRequest;
312 mInWhichUserCallback = UserCallback.GET_LENGTH;
313 }
314 try {
315 mLength = mDataProvider.getLength();
316 mRemainingLength = mLength;
317 } catch (Throwable t) {
318 onError(t);
319 }
320 synchronized (mLock) {
321 mInWhichUserCallback = UserCallback.NOT_IN_CALLBACK;
322 }
323 }
324
325 /**
326 * Creates native objects and attaches them to the underlying request
327 * adapter object. Always called on executor thread.
328 */
329 void attachNativeAdapterToRequest(final long requestAdapter) {
330 synchronized (mLock) {
331 mUploadDataStreamAdapter = nativeAttachUploadDataToRequest(requestAd apter, mLength);
332 }
333 }
334
335 /**
336 * Creates a native CronetUploadDataStreamAdapter and
337 * CronetUploadDataStream for testing.
338 * @return the address of the native CronetUploadDataStream object.
339 */
340 @VisibleForTesting
341 long createUploadDataStreamForTesting() throws IOException {
342 synchronized (mLock) {
343 mUploadDataStreamAdapter = nativeCreateAdapterForTesting();
344 mLength = mDataProvider.getLength();
345 mRemainingLength = mLength;
346 return nativeCreateUploadDataStreamForTesting(mLength, mUploadDataSt reamAdapter);
347 }
348 }
349
350 @VisibleForTesting
351 void setOnDestroyedCallbackForTesting(Runnable onDestroyedCallbackForTesting ) {
352 mOnDestroyedCallbackForTesting = onDestroyedCallbackForTesting;
353 }
354
355 // Native methods are implemented in upload_data_stream_adapter.cc.
356
357 private native long nativeAttachUploadDataToRequest(long urlRequestAdapter,
358 long length);
359
360 private native long nativeCreateAdapterForTesting();
361
362 private native long nativeCreateUploadDataStreamForTesting(long length,
363 long adapter);
364
365 @NativeClassQualifiedName("CronetUploadDataStreamAdapter")
366 private native void nativeOnReadSucceeded(long nativePtr,
367 int bytesRead, boolean finalChunk);
368
369 @NativeClassQualifiedName("CronetUploadDataStreamAdapter")
370 private native void nativeOnRewindSucceeded(long nativePtr);
371
372 @NativeClassQualifiedName("CronetUploadDataStreamAdapter")
373 private static native void nativeDestroy(long nativePtr);
374 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698