OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.photo_picker; |
| 6 |
| 7 import android.app.Service; |
| 8 import android.content.Intent; |
| 9 import android.graphics.Bitmap; |
| 10 import android.os.Bundle; |
| 11 import android.os.IBinder; |
| 12 import android.os.ParcelFileDescriptor; |
| 13 import android.os.RemoteException; |
| 14 import android.os.SystemClock; |
| 15 |
| 16 import org.chromium.base.Log; |
| 17 |
| 18 import java.io.FileDescriptor; |
| 19 import java.io.IOException; |
| 20 |
| 21 /** |
| 22 * A service to accept requests to take image file contents and decode them. |
| 23 */ |
| 24 public class DecoderServiceImpl extends Service { |
| 25 // The keys for the bundle when passing data to and from this service. |
| 26 static final String KEY_FILE_DESCRIPTOR = "file_descriptor"; |
| 27 static final String KEY_FILE_PATH = "file_path"; |
| 28 static final String KEY_IMAGE_BITMAP = "image_bitmap"; |
| 29 static final String KEY_SIZE = "size"; |
| 30 static final String KEY_SUCCESS = "success"; |
| 31 static final String KEY_DECODE_TIME = "decode_time"; |
| 32 |
| 33 // A tag for logging error messages. |
| 34 private static final String TAG = "ImageDecoder"; |
| 35 |
| 36 @Override |
| 37 public void onCreate() { |
| 38 super.onCreate(); |
| 39 } |
| 40 |
| 41 @Override |
| 42 public IBinder onBind(Intent intent) { |
| 43 return mBinder; |
| 44 } |
| 45 |
| 46 private final IDecoderService.Stub mBinder = new IDecoderService.Stub() { |
| 47 public void decodeImage(Bundle payload, IDecoderServiceListener listener
) { |
| 48 Bundle bundle = null; |
| 49 String filePath = ""; |
| 50 int size = 0; |
| 51 try { |
| 52 filePath = payload.getString(KEY_FILE_PATH); |
| 53 ParcelFileDescriptor pfd = payload.getParcelable(KEY_FILE_DESCRI
PTOR); |
| 54 size = payload.getInt(KEY_SIZE); |
| 55 |
| 56 // Setup a minimum viable response to parent process. Will be fl
eshed out |
| 57 // further below. |
| 58 bundle = new Bundle(); |
| 59 bundle.putString(KEY_FILE_PATH, filePath); |
| 60 bundle.putBoolean(KEY_SUCCESS, false); |
| 61 |
| 62 FileDescriptor fd = pfd.getFileDescriptor(); |
| 63 |
| 64 long begin = SystemClock.elapsedRealtime(); |
| 65 Bitmap bitmap = BitmapUtils.decodeBitmapFromFileDescriptor(fd, s
ize); |
| 66 long decodeTime = SystemClock.elapsedRealtime() - begin; |
| 67 |
| 68 try { |
| 69 pfd.close(); |
| 70 } catch (IOException e) { |
| 71 Log.e(TAG, "Closing failed " + filePath + " (size: " + size
+ ") " + e); |
| 72 } |
| 73 |
| 74 if (bitmap == null) { |
| 75 Log.e(TAG, "Decode failed " + filePath + " (size: " + size +
")"); |
| 76 sendReply(listener, bundle); // Sends SUCCESS == false; |
| 77 return; |
| 78 } |
| 79 |
| 80 // The most widely supported, easiest, and reasonably efficient
method is to |
| 81 // decode to an immutable bitmap and just return the bitmap over
binder. It |
| 82 // will internally memcpy itself to ashmem and then just send ov
er the file |
| 83 // descriptor. In the receiving process it will just leave the b
itmap on |
| 84 // ashmem since it's immutable and carry on. |
| 85 bundle.putParcelable(KEY_IMAGE_BITMAP, bitmap); |
| 86 bundle.putBoolean(KEY_SUCCESS, true); |
| 87 bundle.putLong(KEY_DECODE_TIME, decodeTime); |
| 88 sendReply(listener, bundle); |
| 89 bitmap.recycle(); |
| 90 } catch (Exception e) { |
| 91 // This service has no UI and maintains no state so if it crashe
s on |
| 92 // decoding a photo, it is better UX to eat the exception instea
d of showing |
| 93 // a crash dialog and discarding other requests that have alread
y been sent. |
| 94 Log.e(TAG, |
| 95 "Unexpected error during decoding " + filePath + " (size
: " + size + ") " |
| 96 + e); |
| 97 |
| 98 if (bundle != null) sendReply(listener, bundle); |
| 99 } |
| 100 } |
| 101 |
| 102 private void sendReply(IDecoderServiceListener listener, Bundle bundle)
{ |
| 103 try { |
| 104 listener.onDecodeImageDone(bundle); |
| 105 } catch (RemoteException remoteException) { |
| 106 Log.e(TAG, "Remote error while replying: " + remoteException); |
| 107 } |
| 108 } |
| 109 }; |
| 110 } |
OLD | NEW |