Make firmware reading a bit more failsafe #30

master
cpfeiffer 2015-08-04 23:02:36 +02:00
parent bdc9e70e6e
commit 910d9ef398
3 changed files with 49 additions and 36 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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();
}
}