mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-08-31 19:45:27 +02:00
Huawei: Instalattion of apps fixed. Correct bin files support
This commit is contained in:
parent
74b9298a6b
commit
4989334ff4
@ -1,65 +0,0 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HuaweiAppParser {
|
||||
|
||||
public static class AppFileEntry {
|
||||
public String filename;
|
||||
public String folder;
|
||||
public String unknown;
|
||||
public byte[] content;
|
||||
}
|
||||
|
||||
private String packageName;
|
||||
private final ArrayList<AppFileEntry> entries = new ArrayList<>();
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public byte[] getEntryContent(String filename) {
|
||||
for(AppFileEntry en: entries) {
|
||||
if(en.filename.equals(filename)) {
|
||||
return en.content;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] readData(ByteBuffer data) {
|
||||
int len = data.getInt();
|
||||
byte[] newPayload = new byte[len];
|
||||
data.get(newPayload, 0, len);
|
||||
return newPayload;
|
||||
}
|
||||
|
||||
private String readString(ByteBuffer data) {
|
||||
return new String(readData(data));
|
||||
}
|
||||
|
||||
public void parseData(byte[] in) throws Exception {
|
||||
|
||||
ByteBuffer data = ByteBuffer.wrap(in);
|
||||
|
||||
byte magic = data.get();
|
||||
if(magic != (byte)0xbe){
|
||||
throw new Exception("Invalid magic");
|
||||
}
|
||||
this.packageName = readString(data);
|
||||
while(data.remaining() > 0) {
|
||||
int pos = data.position();
|
||||
byte a = data.get();
|
||||
if(a != 0x00)
|
||||
break;
|
||||
data.position(pos);
|
||||
AppFileEntry ent = new AppFileEntry();
|
||||
ent.filename = readString(data);
|
||||
ent.folder = readString(data);
|
||||
ent.unknown = readString(data);
|
||||
ent.content = readData(data);
|
||||
entries.add(ent);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class HuaweiBinAppParser {
|
||||
|
||||
public static class AppFileEntry {
|
||||
public String filename;
|
||||
public String path;
|
||||
public byte[] content;
|
||||
}
|
||||
|
||||
private static final int signHeaderLen = 32;
|
||||
private static final byte[] signMagic = "hw signed app ".getBytes();
|
||||
private static final byte[] signVersion = "1000".getBytes();
|
||||
|
||||
|
||||
private String packageName;
|
||||
private final ArrayList<AppFileEntry> entries = new ArrayList<>();
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public byte[] getEntryContent(String filename) {
|
||||
for(AppFileEntry en: entries) {
|
||||
if(en.filename.equals(filename)) {
|
||||
return en.content;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] readData(ByteBuffer data) {
|
||||
long len = data.getLong();
|
||||
byte[] newPayload = new byte[(int)len];
|
||||
data.get(newPayload, 0, (int)len);
|
||||
return newPayload;
|
||||
}
|
||||
|
||||
private String readString(ByteBuffer data) {
|
||||
int len = data.getInt();
|
||||
byte[] newPayload = new byte[len];
|
||||
data.get(newPayload, 0, len);
|
||||
return new String(newPayload, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private int getSignLen(byte[] in) {
|
||||
byte[] signatureHeader = Arrays.copyOfRange(in, in.length - signHeaderLen, in.length);
|
||||
ByteBuffer signatureHeaderBuf = ByteBuffer.wrap(signatureHeader);
|
||||
byte[] magic = new byte[signMagic.length];
|
||||
signatureHeaderBuf.get(magic, 0, signMagic.length);
|
||||
if(!Arrays.equals(signMagic, magic))
|
||||
return 0;
|
||||
byte[] version = new byte[signVersion.length];
|
||||
signatureHeaderBuf.get(version, 0, signVersion.length);
|
||||
if(!Arrays.equals(signVersion, version))
|
||||
return 0;
|
||||
//NOTE: we need only signature size.
|
||||
return signatureHeaderBuf.getInt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void parseData(byte[] in) throws Exception {
|
||||
//NOTE: Binary app file signed. We should avoid to read this signature.
|
||||
int signLen = getSignLen(in);
|
||||
ByteBuffer data = ByteBuffer.wrap(in);
|
||||
|
||||
byte magic = data.get();
|
||||
if(magic != (byte)0xbe){
|
||||
throw new Exception("Invalid magic");
|
||||
}
|
||||
this.packageName = readString(data);
|
||||
while(data.remaining() > signLen) {
|
||||
AppFileEntry ent = new AppFileEntry();
|
||||
ent.filename = readString(data);
|
||||
ent.path = readString(data);
|
||||
ent.content = readData(data);
|
||||
entries.add(ent);
|
||||
}
|
||||
}
|
||||
}
|
@ -108,16 +108,9 @@ public class HuaweiInstallHandler implements InstallHandler {
|
||||
|
||||
LOG.debug("Initialized HuaweiInstallHandler");
|
||||
} else if (helper.isAPP()) {
|
||||
final HuaweiCoordinatorSupplier huaweiCoordinatorSupplier = (HuaweiCoordinatorSupplier) coordinator;
|
||||
final HuaweiAppManager.AppConfig config = helper.getAppConfig();
|
||||
|
||||
String screenWindow = String.format("%d*%d", huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().height,
|
||||
huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().width);
|
||||
|
||||
String screenShape = huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().screenShape;
|
||||
|
||||
HuaweiAppManager.AppConfig config = helper.getAppconfig();
|
||||
|
||||
this.valid = config.checkDistroFilters(screenShape, screenWindow);
|
||||
this.valid = true; //NOTE: nothing to verify for now
|
||||
|
||||
installActivity.setInstallEnabled(true);
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -26,7 +24,6 @@ public class HuaweiAppManager {
|
||||
public String vendor;
|
||||
public String version;
|
||||
|
||||
JSONObject distroFilters = null;
|
||||
|
||||
public AppConfig(String jsonStr) {
|
||||
|
||||
@ -36,52 +33,11 @@ public class HuaweiAppManager {
|
||||
this.vendor = config.getJSONObject("app").getString("vendor");
|
||||
this.version = config.getJSONObject("app").getJSONObject("version").getString("name");
|
||||
|
||||
parseDistroFilters(config);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error decode app config", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseDistroFilters(JSONObject config) {
|
||||
try {
|
||||
distroFilters = config.getJSONObject("module").getJSONObject("distroFilter");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error decode app config distroFilter", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValInArray(JSONArray arr, String value) throws JSONException {
|
||||
for (int i = 0; i < arr.length(); i++) {
|
||||
if (arr.getString(i).equals(value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean checkDistroFilters(String screenShape, String screenWindow) {
|
||||
if (distroFilters == null)
|
||||
return false;
|
||||
try {
|
||||
boolean screenShapeSupported = false;
|
||||
boolean screenWindowSupported = false;
|
||||
if (distroFilters.has("screenShape")) {
|
||||
JSONArray values = distroFilters.getJSONObject("screenShape").getJSONArray("value");
|
||||
String policy = distroFilters.getJSONObject("screenShape").getString("policy");
|
||||
screenShapeSupported = isValInArray(values, screenShape) && policy.equals("include");
|
||||
}
|
||||
if (distroFilters.has("screenWindow")) {
|
||||
JSONArray values = distroFilters.getJSONObject("screenWindow").getJSONArray("value");
|
||||
String policy = distroFilters.getJSONObject("screenWindow").getString("policy");
|
||||
screenWindowSupported = isValInArray(values, screenWindow) && policy.equals("include");
|
||||
}
|
||||
return screenShapeSupported && screenWindowSupported;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error decode app config distroFilter", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final HuaweiSupportProvider support;
|
||||
|
@ -31,7 +31,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiAppParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiBinAppParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||
@ -71,7 +71,6 @@ public class HuaweiFwHelper {
|
||||
private void parseFile() {
|
||||
if(parseAsApp()) {
|
||||
assert appConfig.bundleName != null;
|
||||
assert appConfig.distroFilters != null;
|
||||
fileType = FileUpload.Filetype.app;
|
||||
} else if (parseAsWatchFace()) {
|
||||
assert watchfaceDescription.screen != null;
|
||||
@ -99,7 +98,7 @@ public class HuaweiFwHelper {
|
||||
buffer.flush();
|
||||
byte[] hap_data = buffer.toByteArray();
|
||||
|
||||
HuaweiAppParser app = new HuaweiAppParser();
|
||||
HuaweiBinAppParser app = new HuaweiBinAppParser();
|
||||
app.parseData(hap_data);
|
||||
|
||||
byte[] config = app.getEntryContent("config.json");
|
||||
@ -212,7 +211,7 @@ public class HuaweiFwHelper {
|
||||
return watchfaceDescription;
|
||||
}
|
||||
|
||||
public HuaweiAppManager.AppConfig getAppconfig() {
|
||||
public HuaweiAppManager.AppConfig getAppConfig() {
|
||||
return appConfig;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user