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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java

Issue 2915863002: Photo Picker dialog: Add UMA statistics. (Closed)
Patch Set: Address feedback from Theresa Created 3 years, 6 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
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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.chrome.browser.photo_picker; 5 package org.chromium.chrome.browser.photo_picker;
6 6
7 import android.content.ComponentName; 7 import android.content.ComponentName;
8 import android.content.Context; 8 import android.content.Context;
9 import android.content.Intent; 9 import android.content.Intent;
10 import android.content.ServiceConnection; 10 import android.content.ServiceConnection;
11 import android.graphics.Bitmap; 11 import android.graphics.Bitmap;
12 import android.os.Bundle; 12 import android.os.Bundle;
13 import android.os.Handler; 13 import android.os.Handler;
14 import android.os.IBinder; 14 import android.os.IBinder;
15 import android.os.Message; 15 import android.os.Message;
16 import android.os.Messenger; 16 import android.os.Messenger;
17 import android.os.ParcelFileDescriptor; 17 import android.os.ParcelFileDescriptor;
18 import android.os.RemoteException; 18 import android.os.RemoteException;
19 import android.os.StrictMode; 19 import android.os.StrictMode;
20 import android.os.SystemClock;
20 21
21 import org.chromium.base.Log; 22 import org.chromium.base.Log;
23 import org.chromium.base.metrics.RecordHistogram;
24 import org.chromium.chrome.browser.download.DownloadUtils;
22 25
23 import java.io.File; 26 import java.io.File;
24 import java.io.FileDescriptor; 27 import java.io.FileDescriptor;
25 import java.io.FileInputStream; 28 import java.io.FileInputStream;
26 import java.io.IOException; 29 import java.io.IOException;
27 import java.lang.ref.WeakReference; 30 import java.lang.ref.WeakReference;
28 import java.util.LinkedHashMap; 31 import java.util.LinkedHashMap;
32 import java.util.concurrent.TimeUnit;
29 33
30 /** 34 /**
31 * A class to communicate with the {@link DecoderService}. 35 * A class to communicate with the {@link DecoderService}.
32 */ 36 */
33 public class DecoderServiceHost { 37 public class DecoderServiceHost {
34 // A tag for logging error messages. 38 // A tag for logging error messages.
35 private static final String TAG = "ImageDecoderHost"; 39 private static final String TAG = "ImageDecoderHost";
36 40
37 /** 41 /**
38 * Interface for notifying clients of the service being ready. 42 * Interface for notifying clients of the service being ready.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 private static class DecoderServiceParams { 90 private static class DecoderServiceParams {
87 // The path to the file containing the bitmap to decode. 91 // The path to the file containing the bitmap to decode.
88 public String mFilePath; 92 public String mFilePath;
89 93
90 // The requested size (width and height) of the bitmap, once decoded. 94 // The requested size (width and height) of the bitmap, once decoded.
91 public int mSize; 95 public int mSize;
92 96
93 // The callback to use to communicate the results of the decoding. 97 // The callback to use to communicate the results of the decoding.
94 ImageDecodedCallback mCallback; 98 ImageDecodedCallback mCallback;
95 99
100 // The timestamp for when the request was sent for decoding.
101 long mTimestamp;
102
96 public DecoderServiceParams(String filePath, int size, ImageDecodedCallb ack callback) { 103 public DecoderServiceParams(String filePath, int size, ImageDecodedCallb ack callback) {
97 mFilePath = filePath; 104 mFilePath = filePath;
98 mSize = size; 105 mSize = size;
99 mCallback = callback; 106 mCallback = callback;
100 } 107 }
101 } 108 }
102 109
103 // Map of file paths to decoder parameters in order of request. 110 // Map of file paths to decoder parameters in order of request.
104 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa shMap<>(); 111 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa shMap<>();
105 LinkedHashMap<String, DecoderServiceParams> getRequests() { 112 LinkedHashMap<String, DecoderServiceParams> getRequests() {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 mRequests.put(filePath, params); 169 mRequests.put(filePath, params);
163 if (mRequests.size() == 1) dispatchNextDecodeImageRequest(); 170 if (mRequests.size() == 1) dispatchNextDecodeImageRequest();
164 } 171 }
165 172
166 /** 173 /**
167 * Dispatches the next image for decoding (from the queue). 174 * Dispatches the next image for decoding (from the queue).
168 */ 175 */
169 private void dispatchNextDecodeImageRequest() { 176 private void dispatchNextDecodeImageRequest() {
170 if (mRequests.entrySet().iterator().hasNext()) { 177 if (mRequests.entrySet().iterator().hasNext()) {
171 DecoderServiceParams params = mRequests.entrySet().iterator().next() .getValue(); 178 DecoderServiceParams params = mRequests.entrySet().iterator().next() .getValue();
179 params.mTimestamp = SystemClock.elapsedRealtime();
172 dispatchDecodeImageRequest(params.mFilePath, params.mSize); 180 dispatchDecodeImageRequest(params.mFilePath, params.mSize);
173 } 181 }
174 } 182 }
175 183
176 /** 184 /**
177 * Ties up all the loose ends from the decoding request (communicates the re sults of the 185 * Ties up all the loose ends from the decoding request (communicates the re sults of the
178 * decoding process back to the client, and takes care of house-keeping chor es regarding 186 * decoding process back to the client, and takes care of house-keeping chor es regarding
179 * the request queue). 187 * the request queue).
180 * @param filePath The path to the image that was just decoded. 188 * @param filePath The path to the image that was just decoded.
181 * @param bitmap The resulting decoded bitmap. 189 * @param bitmap The resulting decoded bitmap.
190 * @param decodeTime The length of time it took to decode the bitmap.
182 */ 191 */
183 public void closeRequest(String filePath, Bitmap bitmap) { 192 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) {
184 DecoderServiceParams params = getRequests().get(filePath); 193 DecoderServiceParams params = getRequests().get(filePath);
185 if (params != null) { 194 if (params != null) {
195 long endRpcCall = SystemClock.elapsedRealtime();
196 RecordHistogram.recordTimesHistogram("Android.PhotoPicker.RequestPro cessTime",
197 endRpcCall - params.mTimestamp, TimeUnit.MILLISECONDS);
198
186 params.mCallback.imageDecodedCallback(filePath, bitmap); 199 params.mCallback.imageDecodedCallback(filePath, bitmap);
200
201 if (decodeTime != -1) {
202 RecordHistogram.recordTimesHistogram(
203 "Android.PhotoPicker.ImageDecodeTime", decodeTime, TimeU nit.MILLISECONDS);
204
205 int sizeInKB = bitmap.getByteCount() / DownloadUtils.BYTES_PER_K ILOBYTE;
206 RecordHistogram.recordCustomCountHistogram(
207 "Android.PhotoPicker.ImageByteCount", sizeInKB, 1, 50000 0, 50);
Theresa 2017/06/01 15:58:04 500MB seems rather high to me; can the max be lowe
208 }
187 getRequests().remove(filePath); 209 getRequests().remove(filePath);
188 } 210 }
189 dispatchNextDecodeImageRequest(); 211 dispatchNextDecodeImageRequest();
190 } 212 }
191 213
192 /** 214 /**
193 * Communicates with the server to decode a single bitmap. 215 * Communicates with the server to decode a single bitmap.
194 * @param filePath The path to the image on disk. 216 * @param filePath The path to the image on disk.
195 * @param size The requested width and height of the resulting bitmap. 217 * @param size The requested width and height of the resulting bitmap.
196 */ 218 */
197 private void dispatchDecodeImageRequest(String filePath, int size) { 219 private void dispatchDecodeImageRequest(String filePath, int size) {
198 // Obtain a file descriptor to send over to the sandboxed process. 220 // Obtain a file descriptor to send over to the sandboxed process.
199 File file = new File(filePath); 221 File file = new File(filePath);
200 FileInputStream inputFile = null; 222 FileInputStream inputFile = null;
201 ParcelFileDescriptor pfd = null; 223 ParcelFileDescriptor pfd = null;
202 Bundle bundle = new Bundle(); 224 Bundle bundle = new Bundle();
203 225
204 // The restricted utility process can't open the file to read the 226 // The restricted utility process can't open the file to read the
205 // contents, so we need to obtain a file descriptor to pass over. 227 // contents, so we need to obtain a file descriptor to pass over.
206 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 228 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
207 try { 229 try {
208 try { 230 try {
209 inputFile = new FileInputStream(file); 231 inputFile = new FileInputStream(file);
210 FileDescriptor fd = inputFile.getFD(); 232 FileDescriptor fd = inputFile.getFD();
211 pfd = ParcelFileDescriptor.dup(fd); 233 pfd = ParcelFileDescriptor.dup(fd);
212 bundle.putParcelable(DecoderService.KEY_FILE_DESCRIPTOR, pfd); 234 bundle.putParcelable(DecoderService.KEY_FILE_DESCRIPTOR, pfd);
213 } catch (IOException e) { 235 } catch (IOException e) {
214 Log.e(TAG, "Unable to obtain FileDescriptor: " + e); 236 Log.e(TAG, "Unable to obtain FileDescriptor: " + e);
215 closeRequest(filePath, null); 237 closeRequest(filePath, null, -1);
216 } 238 }
217 } finally { 239 } finally {
218 try { 240 try {
219 if (inputFile != null) inputFile.close(); 241 if (inputFile != null) inputFile.close();
220 } catch (IOException e) { 242 } catch (IOException e) {
221 Log.e(TAG, "Unable to close inputFile: " + e); 243 Log.e(TAG, "Unable to close inputFile: " + e);
222 } 244 }
223 StrictMode.setThreadPolicy(oldPolicy); 245 StrictMode.setThreadPolicy(oldPolicy);
224 } 246 }
225 247
226 if (pfd == null) return; 248 if (pfd == null) return;
227 249
228 // Prepare and send the data over. 250 // Prepare and send the data over.
229 Message payload = Message.obtain(null, DecoderService.MSG_DECODE_IMAGE); 251 Message payload = Message.obtain(null, DecoderService.MSG_DECODE_IMAGE);
230 payload.replyTo = mMessenger; 252 payload.replyTo = mMessenger;
231 bundle.putString(DecoderService.KEY_FILE_PATH, filePath); 253 bundle.putString(DecoderService.KEY_FILE_PATH, filePath);
232 bundle.putInt(DecoderService.KEY_SIZE, size); 254 bundle.putInt(DecoderService.KEY_SIZE, size);
233 payload.setData(bundle); 255 payload.setData(bundle);
234 try { 256 try {
235 mService.send(payload); 257 mService.send(payload);
236 pfd.close(); 258 pfd.close();
237 } catch (RemoteException e) { 259 } catch (RemoteException e) {
238 Log.e(TAG, "Communications failed (Remote): " + e); 260 Log.e(TAG, "Communications failed (Remote): " + e);
239 closeRequest(filePath, null); 261 closeRequest(filePath, null, -1);
240 } catch (IOException e) { 262 } catch (IOException e) {
241 Log.e(TAG, "Communications failed (IO): " + e); 263 Log.e(TAG, "Communications failed (IO): " + e);
242 closeRequest(filePath, null); 264 closeRequest(filePath, null, -1);
243 } 265 }
244 } 266 }
245 267
246 /** 268 /**
247 * Cancels a request to decode an image (if it hasn't already been dispatche d). 269 * Cancels a request to decode an image (if it hasn't already been dispatche d).
248 * @param filePath The path to the image to cancel decoding. 270 * @param filePath The path to the image to cancel decoding.
249 */ 271 */
250 public void cancelDecodeImage(String filePath) { 272 public void cancelDecodeImage(String filePath) {
251 mRequests.remove(filePath); 273 mRequests.remove(filePath);
252 } 274 }
(...skipping 24 matching lines...) Expand all
277 switch (msg.what) { 299 switch (msg.what) {
278 case DecoderService.MSG_IMAGE_DECODED_REPLY: 300 case DecoderService.MSG_IMAGE_DECODED_REPLY:
279 Bundle payload = msg.getData(); 301 Bundle payload = msg.getData();
280 302
281 // Read the reply back from the service. 303 // Read the reply back from the service.
282 String filePath = payload.getString(DecoderService.KEY_FILE_ PATH); 304 String filePath = payload.getString(DecoderService.KEY_FILE_ PATH);
283 Boolean success = payload.getBoolean(DecoderService.KEY_SUCC ESS); 305 Boolean success = payload.getBoolean(DecoderService.KEY_SUCC ESS);
284 Bitmap bitmap = success 306 Bitmap bitmap = success
285 ? (Bitmap) payload.getParcelable(DecoderService.KEY_ IMAGE_BITMAP) 307 ? (Bitmap) payload.getParcelable(DecoderService.KEY_ IMAGE_BITMAP)
286 : null; 308 : null;
287 host.closeRequest(filePath, bitmap); 309 long decodeTime = payload.getLong(DecoderService.KEY_DECODE_ TIME);
310 host.closeRequest(filePath, bitmap, decodeTime);
288 break; 311 break;
289 default: 312 default:
290 super.handleMessage(msg); 313 super.handleMessage(msg);
291 } 314 }
292 } 315 }
293 } 316 }
294 } 317 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698