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

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

Issue 2613393002: [Cronet] In JavaUrlRequest avoid thread-unsafe access to HttpURLConnection (Closed)
Patch Set: Created 3 years, 11 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.net.impl; 5 package org.chromium.net.impl;
6 6
7 import android.annotation.SuppressLint; 7 import android.annotation.SuppressLint;
8 import android.annotation.TargetApi; 8 import android.annotation.TargetApi;
9 import android.net.TrafficStats; 9 import android.net.TrafficStats;
10 import android.os.Build; 10 import android.os.Build;
(...skipping 12 matching lines...) Expand all
23 import java.net.HttpURLConnection; 23 import java.net.HttpURLConnection;
24 import java.net.URI; 24 import java.net.URI;
25 import java.net.URL; 25 import java.net.URL;
26 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
27 import java.nio.channels.Channels; 27 import java.nio.channels.Channels;
28 import java.nio.channels.ReadableByteChannel; 28 import java.nio.channels.ReadableByteChannel;
29 import java.nio.channels.WritableByteChannel; 29 import java.nio.channels.WritableByteChannel;
30 import java.util.AbstractMap.SimpleEntry; 30 import java.util.AbstractMap.SimpleEntry;
31 import java.util.ArrayList; 31 import java.util.ArrayList;
32 import java.util.Collections; 32 import java.util.Collections;
33 import java.util.LinkedList;
33 import java.util.List; 34 import java.util.List;
34 import java.util.Map; 35 import java.util.Map;
35 import java.util.TreeMap; 36 import java.util.TreeMap;
36 import java.util.concurrent.Executor; 37 import java.util.concurrent.Executor;
37 import java.util.concurrent.RejectedExecutionException; 38 import java.util.concurrent.RejectedExecutionException;
38 import java.util.concurrent.atomic.AtomicBoolean; 39 import java.util.concurrent.atomic.AtomicBoolean;
39 import java.util.concurrent.atomic.AtomicReference; 40 import java.util.concurrent.atomic.AtomicReference;
40 41
41 /** 42 /**
42 * Pure java UrlRequest, backed by {@link HttpURLConnection}. 43 * Pure java UrlRequest, backed by {@link HttpURLConnection}.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 STARTED, 120 STARTED,
120 REDIRECT_RECEIVED, 121 REDIRECT_RECEIVED,
121 AWAITING_FOLLOW_REDIRECT, 122 AWAITING_FOLLOW_REDIRECT,
122 AWAITING_READ, 123 AWAITING_READ,
123 READING, 124 READING,
124 ERROR, 125 ERROR,
125 COMPLETE, 126 COMPLETE,
126 CANCELLED, 127 CANCELLED,
127 } 128 }
128 129
130 // Executor that runs one task at a time on an underlying Executor.
131 private class SeriaizingExecutor implements Executor {
132 private final Executor mUnderlyingExecutor;
133 // Queue of tasks to run. First element is the task currently executing .
134 // Task processing loop is running if queue is not empty. Synchronized on itself.
135 private final List<Runnable> mTaskQueue = new LinkedList<>();
Charles 2017/01/07 03:48:06 Also @GuardedBy
Charles 2017/01/07 03:48:06 Use an ArrayDeque instead - faster, offers methods
pauljensen 2017/01/11 15:29:58 Done.
pauljensen 2017/01/11 15:29:58 Done.
136
137 public SeriaizingExecutor(Executor underlyingExecutor) {
138 mUnderlyingExecutor = underlyingExecutor;
139 }
140
141 @Override
142 public void execute(final Runnable command) {
143 synchronized (mTaskQueue) {
144 mTaskQueue.add(command);
145 // Task processing loop is already running if there are other it ems in mTaskQueue.
146 if (mTaskQueue.size() > 1) {
147 return;
148 }
149 }
150 mUnderlyingExecutor.execute(new Runnable() {
151 @Override
152 public void run() {
153 Runnable task = command;
154 while (true) {
155 task.run();
Charles 2017/01/07 03:48:06 If this throws an exception, other submitted tasks
pauljensen 2017/01/11 15:29:58 Done, note that the Runnables can only be submitte
156 synchronized (mTaskQueue) {
157 mTaskQueue.remove(0);
158 if (mTaskQueue.isEmpty()) {
159 return;
160 }
161 task = mTaskQueue.get(0);
162 }
163 }
164 }
165 });
166 };
167 }
168
129 /** 169 /**
130 * @param executor The executor used for reading and writing from sockets 170 * @param executor The executor used for reading and writing from sockets
131 * @param userExecutor The executor used to dispatch to {@code callback} 171 * @param userExecutor The executor used to dispatch to {@code callback}
132 */ 172 */
133 JavaUrlRequest(Callback callback, final Executor executor, Executor userExec utor, String url, 173 JavaUrlRequest(Callback callback, final Executor executor, Executor userExec utor, String url,
134 String userAgent, boolean allowDirectExecutor) { 174 String userAgent, boolean allowDirectExecutor) {
135 if (url == null) { 175 if (url == null) {
136 throw new NullPointerException("URL is required"); 176 throw new NullPointerException("URL is required");
137 } 177 }
138 if (callback == null) { 178 if (callback == null) {
139 throw new NullPointerException("Listener is required"); 179 throw new NullPointerException("Listener is required");
140 } 180 }
141 if (executor == null) { 181 if (executor == null) {
142 throw new NullPointerException("Executor is required"); 182 throw new NullPointerException("Executor is required");
143 } 183 }
144 if (userExecutor == null) { 184 if (userExecutor == null) {
145 throw new NullPointerException("userExecutor is required"); 185 throw new NullPointerException("userExecutor is required");
146 } 186 }
147 187
148 this.mAllowDirectExecutor = allowDirectExecutor; 188 this.mAllowDirectExecutor = allowDirectExecutor;
149 this.mCallbackAsync = new AsyncUrlRequestCallback(callback, userExecutor ); 189 this.mCallbackAsync = new AsyncUrlRequestCallback(callback, userExecutor );
150 this.mTrafficStatsTag = TrafficStats.getThreadStatsTag(); 190 this.mTrafficStatsTag = TrafficStats.getThreadStatsTag();
151 this.mExecutor = new Executor() { 191 this.mExecutor = new SeriaizingExecutor(new Executor() {
152 @Override 192 @Override
153 public void execute(final Runnable command) { 193 public void execute(final Runnable command) {
154 executor.execute(new Runnable() { 194 executor.execute(new Runnable() {
155 @Override 195 @Override
156 public void run() { 196 public void run() {
157 int oldTag = TrafficStats.getThreadStatsTag(); 197 int oldTag = TrafficStats.getThreadStatsTag();
158 TrafficStats.setThreadStatsTag(mTrafficStatsTag); 198 TrafficStats.setThreadStatsTag(mTrafficStatsTag);
159 try { 199 try {
160 command.run(); 200 command.run();
161 } finally { 201 } finally {
162 TrafficStats.setThreadStatsTag(oldTag); 202 TrafficStats.setThreadStatsTag(oldTag);
163 } 203 }
164 } 204 }
165 }); 205 });
166 } 206 }
167 }; 207 });
168 this.mCurrentUrl = url; 208 this.mCurrentUrl = url;
169 this.mUserAgent = userAgent; 209 this.mUserAgent = userAgent;
170 } 210 }
171 211
172 @Override 212 @Override
173 public void setHttpMethod(String method) { 213 public void setHttpMethod(String method) {
174 checkNotStarted(); 214 checkNotStarted();
175 if (method == null) { 215 if (method == null) {
176 throw new NullPointerException("Method is required."); 216 throw new NullPointerException("Method is required.");
177 } 217 }
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 // Can't throw directly from here, since the delegate execut or could catch this 1012 // Can't throw directly from here, since the delegate execut or could catch this
973 // exception. 1013 // exception.
974 mExecutedInline = new InlineExecutionProhibitedException(); 1014 mExecutedInline = new InlineExecutionProhibitedException();
975 return; 1015 return;
976 } 1016 }
977 mCommand.run(); 1017 mCommand.run();
978 } 1018 }
979 } 1019 }
980 } 1020 }
981 } 1021 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698