From: Ajay Panicker Date: Tue, 21 Jun 2016 00:54:36 +0000 (-0700) Subject: Fix how file size is calculated if not provided X-Git-Tag: android-7.1.2_r17~66^2~4 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=120ba1db4d2c8822473ce2e0623297dbf08449a4;p=android-x86%2Fpackages-apps-Bluetooth.git Fix how file size is calculated if not provided 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 --- diff --git a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java index 97dc0b3f..49ec6dcb 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java +++ b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java @@ -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(); } diff --git a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java index 30f19f81..b8cb641f 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java +++ b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java @@ -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; + } }