Validating firmware word-alignment

This commit is contained in:
Aleksander Nowakowski 2015-07-27 11:11:26 +02:00
parent 3605c1cbdb
commit dcfa4b0f3c
4 changed files with 71 additions and 9 deletions

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" /> <component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="PROJECT" charset="UTF-8" />
</component>
</project> </project>

View File

@ -66,6 +66,7 @@ import no.nordicsemi.android.dfu.internal.exception.DeviceDisconnectedException;
import no.nordicsemi.android.dfu.internal.exception.DfuException; import no.nordicsemi.android.dfu.internal.exception.DfuException;
import no.nordicsemi.android.dfu.internal.exception.HexFileValidationException; import no.nordicsemi.android.dfu.internal.exception.HexFileValidationException;
import no.nordicsemi.android.dfu.internal.exception.RemoteDfuException; import no.nordicsemi.android.dfu.internal.exception.RemoteDfuException;
import no.nordicsemi.android.dfu.internal.exception.SizeValidationException;
import no.nordicsemi.android.dfu.internal.exception.UnknownResponseException; import no.nordicsemi.android.dfu.internal.exception.UnknownResponseException;
import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException; import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
import no.nordicsemi.android.dfu.internal.scanner.BootloaderScannerFactory; import no.nordicsemi.android.dfu.internal.scanner.BootloaderScannerFactory;
@ -378,7 +379,7 @@ public abstract class DfuBaseService extends IntentService {
*/ */
public static final int ERROR_FILE_ERROR = ERROR_MASK | 0x02; public static final int ERROR_FILE_ERROR = ERROR_MASK | 0x02;
/** /**
* Thrown then input file is not a valid HEX or ZIP file. * Thrown when input file is not a valid HEX or ZIP file.
*/ */
public static final int ERROR_FILE_INVALID = ERROR_MASK | 0x03; public static final int ERROR_FILE_INVALID = ERROR_MASK | 0x03;
/** /**
@ -386,7 +387,7 @@ public abstract class DfuBaseService extends IntentService {
*/ */
public static final int ERROR_FILE_IO_EXCEPTION = ERROR_MASK | 0x04; public static final int ERROR_FILE_IO_EXCEPTION = ERROR_MASK | 0x04;
/** /**
* Error thrown then {@code gatt.discoverServices();} returns false. * Error thrown when {@code gatt.discoverServices();} returns false.
*/ */
public static final int ERROR_SERVICE_DISCOVERY_NOT_STARTED = ERROR_MASK | 0x05; public static final int ERROR_SERVICE_DISCOVERY_NOT_STARTED = ERROR_MASK | 0x05;
/** /**
@ -413,6 +414,10 @@ public abstract class DfuBaseService extends IntentService {
* DFU Bootloader version 0.6+ requires sending the Init packet. If such bootloader version is detected, but the init packet has not been set this error is thrown. * DFU Bootloader version 0.6+ requires sending the Init packet. If such bootloader version is detected, but the init packet has not been set this error is thrown.
*/ */
public static final int ERROR_INIT_PACKET_REQUIRED = ERROR_MASK | 0x0B; public static final int ERROR_INIT_PACKET_REQUIRED = ERROR_MASK | 0x0B;
/**
* Thrown when the firmware file is not word-aligned. The firmware size must be dividable by 4 bytes.
*/
public static final int ERROR_FILE_SIZE_INVALID = ERROR_MASK | 0x0C;
/** /**
* Flag set then the DFU target returned a DFU error. Look for DFU specification to get error codes. * Flag set then the DFU target returned a DFU error. Look for DFU specification to get error codes.
*/ */
@ -770,6 +775,8 @@ public abstract class DfuBaseService extends IntentService {
} }
} else { } else {
loge("Connection state change error: " + status + " newState: " + newState); loge("Connection state change error: " + status + " newState: " + newState);
if (newState == BluetoothGatt.STATE_DISCONNECTED)
mConnectionState = STATE_DISCONNECTED;
mPaused = false; mPaused = false;
mError = ERROR_CONNECTION_STATE_MASK | status; mError = ERROR_CONNECTION_STATE_MASK | status;
} }
@ -1178,6 +1185,10 @@ public abstract class DfuBaseService extends IntentService {
mInputStream = is; mInputStream = is;
imageSizeInBytes = mImageSizeInBytes = is.available(); imageSizeInBytes = mImageSizeInBytes = is.available();
if ((imageSizeInBytes % 4) != 0)
throw new SizeValidationException("The new firmware is not word-aligned.");
// Update the file type bit field basing on the ZIP content // Update the file type bit field basing on the ZIP content
if (fileType == TYPE_AUTO && MIME_TYPE_ZIP.equals(mimeType)) { if (fileType == TYPE_AUTO && MIME_TYPE_ZIP.equals(mimeType)) {
final ArchiveInputStream zhis = (ArchiveInputStream) is; final ArchiveInputStream zhis = (ArchiveInputStream) is;
@ -1187,6 +1198,15 @@ public abstract class DfuBaseService extends IntentService {
// Set the Init packet stream in case of a ZIP file // Set the Init packet stream in case of a ZIP file
if (MIME_TYPE_ZIP.equals(mimeType)) { if (MIME_TYPE_ZIP.equals(mimeType)) {
final ArchiveInputStream zhis = (ArchiveInputStream) is; final ArchiveInputStream zhis = (ArchiveInputStream) is;
// Validate sizes
if ((fileType & TYPE_APPLICATION) > 0 && (zhis.applicationImageSize() % 4) != 0)
throw new SizeValidationException("Application firmware is not word-aligned.");
if ((fileType & TYPE_BOOTLOADER) > 0 && (zhis.bootloaderImageSize() % 4) != 0)
throw new SizeValidationException("Bootloader firmware is not word-aligned.");
if ((fileType & TYPE_SOFT_DEVICE) > 0 && (zhis.softDeviceImageSize() % 4) != 0)
throw new SizeValidationException("Soft Device firmware is not word-aligned.");
if (fileType == TYPE_APPLICATION) { if (fileType == TYPE_APPLICATION) {
if (zhis.getApplicationInit() != null) if (zhis.getApplicationInit() != null)
initIs = new ByteArrayInputStream(zhis.getApplicationInit()); initIs = new ByteArrayInputStream(zhis.getApplicationInit());
@ -1204,6 +1224,10 @@ public abstract class DfuBaseService extends IntentService {
loge("An exception occurred while opening file", e); loge("An exception occurred while opening file", e);
updateProgressNotification(ERROR_FILE_NOT_FOUND); updateProgressNotification(ERROR_FILE_NOT_FOUND);
return; return;
} catch (final SizeValidationException e) {
loge("Firmware not word-aligned", e);
updateProgressNotification(ERROR_FILE_SIZE_INVALID);
return;
} catch (final IOException e) { } catch (final IOException e) {
loge("An exception occurred while calculating file size", e); loge("An exception occurred while calculating file size", e);
updateProgressNotification(ERROR_FILE_ERROR); updateProgressNotification(ERROR_FILE_ERROR);
@ -2844,12 +2868,10 @@ public abstract class DfuBaseService extends IntentService {
} }
private void loge(final String message) { private void loge(final String message) {
if (BuildConfig.DEBUG)
Log.e(TAG, message); Log.e(TAG, message);
} }
private void loge(final String message, final Throwable e) { private void loge(final String message, final Throwable e) {
if (BuildConfig.DEBUG)
Log.e(TAG, message, e); Log.e(TAG, message, e);
} }

View File

@ -0,0 +1,37 @@
/*************************************************************************************************************************************************
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
************************************************************************************************************************************************/
package no.nordicsemi.android.dfu.internal.exception;
import java.io.IOException;
/**
* This exception is thrown when the firmware size is not word-aligned (number of bytes does not divide by 4).
* This is the requirement for the DFU Bootloader.
*/
public class SizeValidationException extends IOException {
private static final long serialVersionUID = -6467104024030837875L;
public SizeValidationException(final String message) {
super(message);
}
}

View File

@ -151,6 +151,8 @@ public class GattError {
return "DFU FILE ERROR"; return "DFU FILE ERROR";
case DfuBaseService.ERROR_FILE_INVALID: case DfuBaseService.ERROR_FILE_INVALID:
return "DFU NOT A VALID HEX FILE"; return "DFU NOT A VALID HEX FILE";
case DfuBaseService.ERROR_FILE_SIZE_INVALID:
return "DFU FILE NOT WORD ALIGNED";
case DfuBaseService.ERROR_FILE_IO_EXCEPTION: case DfuBaseService.ERROR_FILE_IO_EXCEPTION:
return "DFU IO EXCEPTION"; return "DFU IO EXCEPTION";
case DfuBaseService.ERROR_FILE_NOT_FOUND: case DfuBaseService.ERROR_FILE_NOT_FOUND: