OSDN Git Service

Fix how file size is calculated if not provided
authorAjay Panicker <apanicke@google.com>
Tue, 21 Jun 2016 00:54:36 +0000 (17:54 -0700)
committerAjay Panicker <apanicke@google.com>
Tue, 21 Jun 2016 21:15:19 +0000 (14:15 -0700)
Currently if there is no file size provided, InputStream.available()
is used to guess how many bytes are available. According to the
java documentation, available() should not be used to calculate
file sizes, as it isn't guarenteed to return the total number of
bytes in the stream. This is fixed by reading the stream to
calculate the length, then resetting the stream.

Bug: 29334784
Change-Id: Ic851c46d053157e4d5404352d76f9ff87a509607

src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java

index 97dc0b3..49ec6dc 100644 (file)
@@ -416,19 +416,9 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
 
                         position += readLength;
 
-                        if (position != fileInfo.mLength) {
-                            mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT);
-                            synchronized (this) {
-                                mWaitingForRemote = false;
-                            }
-                        } else {
-                            // if file length is smaller than buffer size, only one packet
-                            // so block point is here
-                            outputStream.close();
-                            mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT);
-                            synchronized (this) {
-                                mWaitingForRemote = false;
-                            }
+                        mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT);
+                        synchronized (this) {
+                            mWaitingForRemote = false;
                         }
                         /* check remote accept or reject */
                         responseCode = putOperation.getResponseCode();
@@ -446,36 +436,34 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
                         }
                     }
 
-                    while (!mInterrupted && okToProceed && (position != fileInfo.mLength)) {
-                        {
-                            if (V) timestamp = System.currentTimeMillis();
-
-                            readLength = a.read(buffer, 0, outputBufferSize);
-                            outputStream.write(buffer, 0, readLength);
-
-                            /* check remote abort */
-                            responseCode = putOperation.getResponseCode();
-                            if (V) Log.v(TAG, "Response code is " + responseCode);
-                            if (responseCode != ResponseCodes.OBEX_HTTP_CONTINUE
-                                    && responseCode != ResponseCodes.OBEX_HTTP_OK) {
-                                /* abort happens */
-                                okToProceed = false;
-                            } else {
-                                position += readLength;
-                                if (V) {
-                                    Log.v(TAG, "Sending file position = " + position
-                                            + " readLength " + readLength + " bytes took "
-                                            + (System.currentTimeMillis() - timestamp) + " ms");
-                                }
-                                // Update the Progress Bar only if there is change in percentage
-                                percent = position * 100 / fileInfo.mLength;
-                                if (percent > prevPercent) {
-                                    updateValues = new ContentValues();
-                                    updateValues.put(BluetoothShare.CURRENT_BYTES, position);
-                                    mContext1.getContentResolver().update(contentUri, updateValues,
-                                            null, null);
-                                    prevPercent = percent;
-                                }
+                    while (!mInterrupted && okToProceed && (position < fileInfo.mLength)) {
+                        if (V) timestamp = System.currentTimeMillis();
+
+                        readLength = a.read(buffer, 0, outputBufferSize);
+                        outputStream.write(buffer, 0, readLength);
+
+                        /* check remote abort */
+                        responseCode = putOperation.getResponseCode();
+                        if (V) Log.v(TAG, "Response code is " + responseCode);
+                        if (responseCode != ResponseCodes.OBEX_HTTP_CONTINUE
+                                && responseCode != ResponseCodes.OBEX_HTTP_OK) {
+                            /* abort happens */
+                            okToProceed = false;
+                        } else {
+                            position += readLength;
+                            if (V) {
+                                Log.v(TAG, "Sending file position = " + position
+                                        + " readLength " + readLength + " bytes took "
+                                        + (System.currentTimeMillis() - timestamp) + " ms");
+                            }
+                            // Update the Progress Bar only if there is change in percentage
+                            percent = position * 100 / fileInfo.mLength;
+                            if (percent > prevPercent) {
+                                updateValues = new ContentValues();
+                                updateValues.put(BluetoothShare.CURRENT_BYTES, position);
+                                mContext1.getContentResolver().update(contentUri, updateValues,
+                                        null, null);
+                                prevPercent = percent;
                             }
                         }
                     }
@@ -491,7 +479,6 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
                     } else if (!mInterrupted && position == fileInfo.mLength) {
                         Log.i(TAG, "SendFile finished send out file " + fileInfo.mFileName
                                 + " length " + fileInfo.mLength);
-                        outputStream.close();
                     } else {
                         error = true;
                         status = BluetoothShare.STATUS_CANCELED;
@@ -537,6 +524,9 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
                     if (inputStream != null) {
                         inputStream.close();
                     }
+                    if (outputStream != null) {
+                        outputStream.close();
+                    }
                     if (putOperation != null) {
                         putOperation.close();
                     }
index 30f19f8..b8cb641 100644 (file)
@@ -121,8 +121,10 @@ public class BluetoothOppSendFileInfo {
             if (metadataCursor != null) {
                 try {
                     if (metadataCursor.moveToFirst()) {
-                        fileName = metadataCursor.getString(0);
-                        length = metadataCursor.getLong(1);
+                        fileName = metadataCursor.getString(
+                                metadataCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+                        length = metadataCursor.getLong(
+                                metadataCursor.getColumnIndex(OpenableColumns.SIZE));
                         if (D) Log.d(TAG, "fileName = " + fileName + " length = " + length);
                     }
                 } finally {
@@ -156,11 +158,23 @@ public class BluetoothOppSendFileInfo {
                             "), using stat length (" + Long.toString(statLength) + ")");
                     length = statLength;
                 }
+
                 try {
                     // This creates an auto-closing input-stream, so
                     // the file descriptor will be closed whenever the InputStream
                     // is closed.
                     is = fd.createInputStream();
+
+                    // If the database doesn't contain the file size, get the size
+                    // by reading through the entire stream
+                    if (length == 0) {
+                        length = getStreamSize(is);
+                        Log.w(TAG, "File length not provided. Length from stream = "
+                                   + length);
+                        // Reset the stream
+                        fd = contentResolver.openAssetFileDescriptor(uri, "r");
+                        is = fd.createInputStream();
+                    }
                 } catch (IOException e) {
                     try {
                         fd.close();
@@ -172,25 +186,39 @@ public class BluetoothOppSendFileInfo {
                 // Ignore
             }
         }
+
         if (is == null) {
             try {
                 is = (FileInputStream) contentResolver.openInputStream(uri);
+
+                // If the database doesn't contain the file size, get the size
+                // by reading through the entire stream
+                if (length == 0) {
+                    length = getStreamSize(is);
+                    // Reset the stream
+                    is = (FileInputStream) contentResolver.openInputStream(uri);
+                }
             } catch (FileNotFoundException e) {
                 return SEND_FILE_INFO_ERROR;
-            }
-        }
-        // If we can not get file length from content provider, we can try to
-        // get the length via the opened stream.
-        if (length == 0) {
-            try {
-                length = is.available();
-                if (V) Log.v(TAG, "file length is " + length);
             } catch (IOException e) {
-                Log.e(TAG, "Read stream exception: ", e);
                 return SEND_FILE_INFO_ERROR;
             }
         }
 
+        if (length == 0) {
+            Log.e(TAG, "Could not determine size of file");
+            return SEND_FILE_INFO_ERROR;
+        }
+
         return new BluetoothOppSendFileInfo(fileName, contentType, length, is, 0);
     }
+
+    private static long getStreamSize(FileInputStream is) throws IOException {
+        long length = 0;
+        byte unused[] = new byte[4096];
+        while (is.available() > 0) {
+            length += is.read(unused, 0, 4096);
+        }
+        return length;
+    }
 }