diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java index f7f91139..6195a29c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java @@ -8,9 +8,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.Locale; +import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; + public class MiBandFWHelper { private static final Logger LOG = LoggerFactory.getLogger(MiBandFWHelper.class); @@ -29,41 +32,25 @@ public class MiBandFWHelper { 16779568 //1.0.9.48 tested by developer }; - public MiBandFWHelper(Uri uri, Context context) { + public MiBandFWHelper(Uri uri, Context context) throws IOException { this.uri = uri; cr = context.getContentResolver(); - InputStream fin; - - try { - fin = new BufferedInputStream(cr.openInputStream(uri)); - this.fw = new byte[fin.available()]; - fin.read(fw); - fin.close(); - + try (InputStream in = new BufferedInputStream(cr.openInputStream(uri))){ + this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB + if (fw.length > firmwareVersionMajor && fw[firmwareVersionMajor] != 1) { + throw new IOException("Firmware major version should be 1, probably this isn't a MiBand firmware."); + } } catch (Exception e) { - e.printStackTrace(); - this.fw = null; + throw new IOException("Error reading firmware file: " + uri.toString(), e); } - - if (fw[firmwareVersionMajor] != 1) { - LOG.error("Firmware major version should be 1, probably this isn't a MiBand firmware."); - this.fw = null; - } - } public int getFirmwareVersion() { - if (fw == null) { - return -1; - } return (fw[firmwareVersionMajor] << 24) | (fw[firmwareVersionMinor] << 16) | (fw[firmwareVersionRevision] << 8) | fw[firmwareVersionBuild]; } public String getHumanFirmwareVersion() { - if (fw == null) { - return "UNK"; - } return String.format(Locale.US, "%d.%d.%d.%d", fw[firmwareVersionMajor], fw[firmwareVersionMinor], fw[firmwareVersionRevision], fw[firmwareVersionBuild]); } @@ -94,5 +81,4 @@ public class MiBandFWHelper { crc &= 0xffff; return crc; } - } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index b4c502fe..47759522 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -592,21 +592,23 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { @Override public void onInstallApp(Uri uri) { - MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext()); - String mMac = getDevice().getAddress(); - String[] mMacOctets = mMac.split(":"); + try { + MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext()); + String mMac = getDevice().getAddress(); + String[] mMacOctets = mMac.split(":"); - int newFwVersion = mFwHelper.getFirmwareVersion(); - int oldFwVersion = mDeviceInfo.getFirmwareVersion(); - int checksum = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5])) ^ mFwHelper.getCRC16(mFwHelper.getFw()); + int newFwVersion = mFwHelper.getFirmwareVersion(); + int oldFwVersion = mDeviceInfo.getFirmwareVersion(); + int checksum = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5])) ^ mFwHelper.getCRC16(mFwHelper.getFw()); - if (sendFirmwareInfo(oldFwVersion, newFwVersion, mFwHelper.getFw().length, checksum)) { - firmwareInfoSent = true; - newFirmware = mFwHelper.getFw(); - //the firmware will be sent by the notification listener if the band confirms that the metadata are ok. + if (sendFirmwareInfo(oldFwVersion, newFwVersion, mFwHelper.getFw().length, checksum)) { + firmwareInfoSent = true; + newFirmware = mFwHelper.getFw(); + //the firmware will be sent by the notification listener if the band confirms that the metadata are ok. + } + } catch (IOException ex) { + GB.toast(getContext(), "Firmware cannot be installed: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR); } - - return; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java index 3439c930..bbaed7d0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java @@ -1,9 +1,11 @@ package nodomain.freeyourgadget.gadgetbridge.util; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.channels.FileChannel; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -44,4 +46,27 @@ public class FileUtils { } return dir; } + + /** + * Reads the contents of the given InputStream into a byte array, but does not + * read more than maxLen bytes. + * @param in the stream to read from + * @param maxLen the maximum number of bytes to read/return + * @return the bytes read from the InputStream + * @throws IOException when reading failed or when maxLen was exceeded + */ + public static byte[] readAll(InputStream in, long maxLen) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(8192, in.available())); + byte[] buf = new byte[8192]; + int read = 0; + long totalRead = 0; + while ((read = in.read(buf)) > 0) { + out.write(buf, 0, read); + totalRead += read; + if (totalRead > maxLen) { + throw new IOException("Too much data to read into memory. Got already " + totalRead + buf); + } + } + return out.toByteArray(); + } } \ No newline at end of file