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

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

Issue 2948583002: Photo Picker dialog: Convert to AIDL for easier security review. (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;
14 import android.os.IBinder; 13 import android.os.IBinder;
15 import android.os.Message;
16 import android.os.Messenger;
17 import android.os.ParcelFileDescriptor; 14 import android.os.ParcelFileDescriptor;
18 import android.os.RemoteException; 15 import android.os.RemoteException;
19 import android.os.StrictMode; 16 import android.os.StrictMode;
20 import android.os.SystemClock; 17 import android.os.SystemClock;
21 18
22 import org.chromium.base.Log; 19 import org.chromium.base.Log;
20 import org.chromium.base.ThreadUtils;
23 import org.chromium.base.metrics.RecordHistogram; 21 import org.chromium.base.metrics.RecordHistogram;
24 import org.chromium.chrome.browser.util.ConversionUtils; 22 import org.chromium.chrome.browser.util.ConversionUtils;
25 23
26 import java.io.File; 24 import java.io.File;
27 import java.io.FileDescriptor; 25 import java.io.FileDescriptor;
28 import java.io.FileInputStream; 26 import java.io.FileInputStream;
29 import java.io.IOException; 27 import java.io.IOException;
30 import java.lang.ref.WeakReference;
31 import java.util.LinkedHashMap; 28 import java.util.LinkedHashMap;
32 import java.util.concurrent.TimeUnit; 29 import java.util.concurrent.TimeUnit;
33 30
34 /** 31 /**
35 * A class to communicate with the {@link DecoderService}. 32 * A class to communicate with the {@link DecoderService}.
36 */ 33 */
37 public class DecoderServiceHost { 34 public class DecoderServiceHost extends IDecoderServiceCallback.Stub {
38 // A tag for logging error messages. 35 // A tag for logging error messages.
39 private static final String TAG = "ImageDecoderHost"; 36 private static final String TAG = "ImageDecoderHost";
40 37
38 IDecoderService mIRemoteService;
39 private ServiceConnection mConnection = new ServiceConnection() {
40 public void onServiceConnected(ComponentName className, IBinder service) {
41 mIRemoteService = IDecoderService.Stub.asInterface(service);
42 mBound = true;
43 mCallback.serviceReady();
44 }
45
46 public void onServiceDisconnected(ComponentName className) {
47 Log.e(TAG, "Service has unexpectedly disconnected");
48 mIRemoteService = null;
49 mBound = false;
50 }
51 };
52
41 /** 53 /**
42 * Interface for notifying clients of the service being ready. 54 * Interface for notifying clients of the service being ready.
43 */ 55 */
44 public interface ServiceReadyCallback { 56 public interface ServiceReadyCallback {
45 /** 57 /**
46 * A function to define to receive a notification once the service is up and running. 58 * A function to define to receive a notification once the service is up and running.
47 */ 59 */
48 void serviceReady(); 60 void serviceReady();
49 } 61 }
50 62
51 /** 63 /**
52 * An interface notifying clients when an image has finished decoding. 64 * An interface notifying clients when an image has finished decoding.
53 */ 65 */
54 public interface ImageDecodedCallback { 66 public interface ImageDecodedCallback {
55 /** 67 /**
56 * A function to define to receive a notification that an image has been decoded. 68 * A function to define to receive a notification that an image has been decoded.
57 * @param filePath The file path for the newly decoded image. 69 * @param filePath The file path for the newly decoded image.
58 * @param bitmap The results of the decoding (or placeholder image, if f ailed). 70 * @param bitmap The results of the decoding (or placeholder image, if f ailed).
59 */ 71 */
60 void imageDecodedCallback(String filePath, Bitmap bitmap); 72 void imageDecodedCallback(String filePath, Bitmap bitmap);
61 } 73 }
62 74
63 /** 75 /**
64 * Class for interacting with the main interface of the service.
65 */
66 private class DecoderServiceConnection implements ServiceConnection {
67 // The callback to use to notify the service being ready.
68 private ServiceReadyCallback mCallback;
69
70 public DecoderServiceConnection(ServiceReadyCallback callback) {
71 mCallback = callback;
72 }
73
74 // Called when a connection to the service has been established.
75 public void onServiceConnected(ComponentName name, IBinder service) {
76 mService = new Messenger(service);
77 mBound = true;
78 mCallback.serviceReady();
79 }
80
81 // Called when a connection to the service has been lost.
82 public void onServiceDisconnected(ComponentName name) {
83 mBound = false;
84 }
85 }
86
87 /**
88 * Class for keeping track of the data involved with each request. 76 * Class for keeping track of the data involved with each request.
89 */ 77 */
90 private static class DecoderServiceParams { 78 private static class DecoderServiceParams {
91 // The path to the file containing the bitmap to decode. 79 // The path to the file containing the bitmap to decode.
92 public String mFilePath; 80 public String mFilePath;
93 81
94 // The requested size (width and height) of the bitmap, once decoded. 82 // The requested size (width and height) of the bitmap, once decoded.
95 public int mSize; 83 public int mSize;
96 84
97 // The callback to use to communicate the results of the decoding. 85 // The callback to use to communicate the results of the decoding.
(...skipping 11 matching lines...) Expand all
109 97
110 // Map of file paths to decoder parameters in order of request. 98 // Map of file paths to decoder parameters in order of request.
111 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa shMap<>(); 99 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa shMap<>();
112 LinkedHashMap<String, DecoderServiceParams> getRequests() { 100 LinkedHashMap<String, DecoderServiceParams> getRequests() {
113 return mRequests; 101 return mRequests;
114 } 102 }
115 103
116 // The callback used to notify the client when the service is ready. 104 // The callback used to notify the client when the service is ready.
117 private ServiceReadyCallback mCallback; 105 private ServiceReadyCallback mCallback;
118 106
119 // Messenger for communicating with the remote service.
120 Messenger mService = null;
121
122 // Our service connection to the {@link DecoderService}.
123 private DecoderServiceConnection mConnection;
124
125 // Flag indicating whether we are bound to the service. 107 // Flag indicating whether we are bound to the service.
126 boolean mBound; 108 boolean mBound;
127 109
128 // The inbound messenger used by the remote service to communicate with us. 110 private Context mContext;
Robert Sesek 2017/06/20 20:49:43 final?
129 final Messenger mMessenger = new Messenger(new IncomingHandler(this));
130 111
131 /** 112 /**
132 * The DecoderServiceHost constructor. 113 * The DecoderServiceHost constructor.
133 * @param callback The callback to use when communicating back to the client . 114 * @param callback The callback to use when communicating back to the client .
134 */ 115 */
135 public DecoderServiceHost(ServiceReadyCallback callback) { 116 public DecoderServiceHost(ServiceReadyCallback callback, Context context) {
136 mCallback = callback; 117 mCallback = callback;
118 mContext = context;
137 } 119 }
138 120
139 /** 121 /**
140 * Initiate binding with the {@link DecoderService}. 122 * Initiate binding with the {@link DecoderService}.
141 * @param context The context to use. 123 * @param context The context to use.
142 */ 124 */
143 public void bind(Context context) { 125 public void bind(Context context) {
144 mConnection = new DecoderServiceConnection(mCallback); 126 Intent intent = new Intent(mContext, DecoderService.class);
145 Intent intent = new Intent(context, DecoderService.class); 127 intent.setAction(IDecoderService.class.getName());
146 context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 128 mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
147 } 129 }
148 130
149 /** 131 /**
150 * Unbind from the {@link DecoderService}. 132 * Unbind from the {@link DecoderService}.
151 * @param context The context to use. 133 * @param context The context to use.
152 */ 134 */
153 public void unbind(Context context) { 135 public void unbind(Context context) {
154 if (mBound) { 136 if (mBound) {
155 context.unbindService(mConnection); 137 context.unbindService(mConnection);
156 mBound = false; 138 mBound = false;
(...skipping 17 matching lines...) Expand all
174 * Dispatches the next image for decoding (from the queue). 156 * Dispatches the next image for decoding (from the queue).
175 */ 157 */
176 private void dispatchNextDecodeImageRequest() { 158 private void dispatchNextDecodeImageRequest() {
177 if (mRequests.entrySet().iterator().hasNext()) { 159 if (mRequests.entrySet().iterator().hasNext()) {
178 DecoderServiceParams params = mRequests.entrySet().iterator().next() .getValue(); 160 DecoderServiceParams params = mRequests.entrySet().iterator().next() .getValue();
179 params.mTimestamp = SystemClock.elapsedRealtime(); 161 params.mTimestamp = SystemClock.elapsedRealtime();
180 dispatchDecodeImageRequest(params.mFilePath, params.mSize); 162 dispatchDecodeImageRequest(params.mFilePath, params.mSize);
181 } 163 }
182 } 164 }
183 165
166 @Override
167 public void onDecodeImageDone(final Bundle payload) {
168 ThreadUtils.runOnUiThread(new Runnable() {
169 @Override
170 public void run() {
171 // Read the reply back from the service.
172 String filePath = payload.getString(DecoderService.KEY_FILE_PATH );
173 Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS) ;
174 Bitmap bitmap = success
175 ? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAG E_BITMAP)
176 : null;
177 long decodeTime = payload.getLong(DecoderService.KEY_DECODE_TIME );
178 closeRequest(filePath, bitmap, decodeTime);
179 }
180 });
181 }
182
184 /** 183 /**
185 * Ties up all the loose ends from the decoding request (communicates the re sults of the 184 * Ties up all the loose ends from the decoding request (communicates the re sults of the
186 * decoding process back to the client, and takes care of house-keeping chor es regarding 185 * decoding process back to the client, and takes care of house-keeping chor es regarding
187 * the request queue). 186 * the request queue).
188 * @param filePath The path to the image that was just decoded. 187 * @param filePath The path to the image that was just decoded.
189 * @param bitmap The resulting decoded bitmap. 188 * @param bitmap The resulting decoded bitmap.
190 * @param decodeTime The length of time it took to decode the bitmap. 189 * @param decodeTime The length of time it took to decode the bitmap.
191 */ 190 */
192 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) { 191 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) {
193 DecoderServiceParams params = getRequests().get(filePath); 192 DecoderServiceParams params = getRequests().get(filePath);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 if (inputFile != null) inputFile.close(); 240 if (inputFile != null) inputFile.close();
242 } catch (IOException e) { 241 } catch (IOException e) {
243 Log.e(TAG, "Unable to close inputFile: " + e); 242 Log.e(TAG, "Unable to close inputFile: " + e);
244 } 243 }
245 StrictMode.setThreadPolicy(oldPolicy); 244 StrictMode.setThreadPolicy(oldPolicy);
246 } 245 }
247 246
248 if (pfd == null) return; 247 if (pfd == null) return;
249 248
250 // Prepare and send the data over. 249 // Prepare and send the data over.
251 Message payload = Message.obtain(null, DecoderService.MSG_DECODE_IMAGE);
252 payload.replyTo = mMessenger;
253 bundle.putString(DecoderService.KEY_FILE_PATH, filePath); 250 bundle.putString(DecoderService.KEY_FILE_PATH, filePath);
254 bundle.putInt(DecoderService.KEY_SIZE, size); 251 bundle.putInt(DecoderService.KEY_SIZE, size);
255 payload.setData(bundle);
256 try { 252 try {
257 mService.send(payload); 253 mIRemoteService.decodeImage(bundle, this);
Theresa 2017/06/20 16:53:12 Does the service automatically run this on a diffe
Finnur 2017/06/20 20:55:05 No, no problem. This is exactly the kind of thing
Theresa 2017/06/21 14:58:36 Thanks for the link, that is very helpful. So thi
Finnur 2017/06/21 15:20:34 Yes. Done.
258 pfd.close(); 254 pfd.close();
259 } catch (RemoteException e) { 255 } catch (RemoteException e) {
260 Log.e(TAG, "Communications failed (Remote): " + e); 256 Log.e(TAG, "Communications failed (Remote): " + e);
261 closeRequest(filePath, null, -1); 257 closeRequest(filePath, null, -1);
262 } catch (IOException e) { 258 } catch (IOException e) {
263 Log.e(TAG, "Communications failed (IO): " + e); 259 Log.e(TAG, "Communications failed (IO): " + e);
264 closeRequest(filePath, null, -1); 260 closeRequest(filePath, null, -1);
265 } 261 }
266 } 262 }
267 263
268 /** 264 /**
269 * Cancels a request to decode an image (if it hasn't already been dispatche d). 265 * Cancels a request to decode an image (if it hasn't already been dispatche d).
270 * @param filePath The path to the image to cancel decoding. 266 * @param filePath The path to the image to cancel decoding.
271 */ 267 */
272 public void cancelDecodeImage(String filePath) { 268 public void cancelDecodeImage(String filePath) {
273 mRequests.remove(filePath); 269 mRequests.remove(filePath);
274 } 270 }
275
276 /**
277 * A class for handling communications from the service to us.
278 */
279 static class IncomingHandler extends Handler {
280 // The DecoderServiceHost object to communicate with.
281 private final WeakReference<DecoderServiceHost> mHost;
282
283 /**
284 * Constructor for IncomingHandler.
285 * @param host The DecoderServiceHost object to communicate with.
286 */
287 IncomingHandler(DecoderServiceHost host) {
288 mHost = new WeakReference<DecoderServiceHost>(host);
289 }
290
291 @Override
292 public void handleMessage(Message msg) {
293 DecoderServiceHost host = mHost.get();
294 if (host == null) {
295 super.handleMessage(msg);
296 return;
297 }
298
299 switch (msg.what) {
300 case DecoderService.MSG_IMAGE_DECODED_REPLY:
301 Bundle payload = msg.getData();
302
303 // Read the reply back from the service.
304 String filePath = payload.getString(DecoderService.KEY_FILE_ PATH);
305 Boolean success = payload.getBoolean(DecoderService.KEY_SUCC ESS);
306 Bitmap bitmap = success
307 ? (Bitmap) payload.getParcelable(DecoderService.KEY_ IMAGE_BITMAP)
308 : null;
309 long decodeTime = payload.getLong(DecoderService.KEY_DECODE_ TIME);
310 host.closeRequest(filePath, bitmap, decodeTime);
311 break;
312 default:
313 super.handleMessage(msg);
314 }
315 }
316 }
317 } 271 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698