Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class ResourcesDecoder {
private final ApkInfo mApkInfo;
private final ResTable mResTable;
private final Map<String, String> mResFileMapping;
private boolean mIncludeAuxiliaryPublicXml;

public ResourcesDecoder(Config config, ApkInfo apkInfo) {
mConfig = config;
Expand All @@ -71,6 +72,18 @@ public void loadMainPkg() throws AndrolibException {
mResTable.loadMainPkg(mApkInfo.getApkFile());
}

public void loadAuxiliaryPkg(ExtFile apkFile) throws AndrolibException {
mResTable.loadAuxiliaryPkg(apkFile);
}

public void loadAuxiliaryPkgs(Collection<ExtFile> apkFiles) throws AndrolibException {
mResTable.loadAuxiliaryPkgs(apkFiles);
}

public void setIncludeAuxiliaryPublicXml(boolean includeAuxiliaryPublicXml) {
mIncludeAuxiliaryPublicXml = includeAuxiliaryPublicXml;
}

public void decodeManifest(File apkDir) throws AndrolibException {
if (!mApkInfo.hasManifest()) {
return;
Expand Down Expand Up @@ -158,7 +171,7 @@ public void decodeResources(File apkDir) throws AndrolibException {
return;
}

mResTable.loadMainPkg(mApkInfo.getApkFile());
loadMainPkg();

ResStreamDecoderContainer decoders = new ResStreamDecoderContainer();
decoders.setDecoder("raw", new ResRawStreamDecoder());
Expand Down Expand Up @@ -193,7 +206,7 @@ public void decodeResources(File apkDir) throws AndrolibException {
generateValuesFile(valuesFile, outDir, xmlSerializer);
}

generatePublicXml(pkg, outDir, xmlSerializer);
generatePublicXml(pkg, outDir, xmlSerializer, mIncludeAuxiliaryPublicXml);
}

AndrolibException decodeError = axmlParser.getFirstError();
Expand Down Expand Up @@ -237,14 +250,14 @@ private void generateValuesFile(ResValuesFile valuesFile, Directory resDir, XmlS
}
}

private void generatePublicXml(ResPackage pkg, Directory resDir, XmlSerializer serial)
private void generatePublicXml(ResPackage pkg, Directory resDir, XmlSerializer serial, boolean includeAuxiliary)
throws AndrolibException {
try (OutputStream out = resDir.getFileOutput("values/public.xml")) {
serial.setOutput(out, null);
serial.startDocument(null, null);
serial.startTag(null, "resources");

for (ResResSpec spec : pkg.listResSpecs()) {
for (ResResSpec spec : mResTable.listResSpecs(pkg, includeAuxiliary)) {
serial.startTag(null, "public");
serial.attribute(null, "type", spec.getType().getName());
serial.attribute(null, "name", spec.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public class ResTable {
private final ApkInfo mApkInfo;
private final Map<Integer, ResPackage> mPackagesById;
private final Map<String, ResPackage> mPackagesByName;
private final Map<ResID, ResResSpec> mAuxiliaryResSpecs;
private final Map<String, ResResSpec> mAuxiliaryResSpecsByName;
private final Set<ResPackage> mMainPackages;
private final Set<ResPackage> mFramePackages;

Expand All @@ -63,6 +65,8 @@ public ResTable(Config config, ApkInfo apkInfo) {
mApkInfo = apkInfo;
mPackagesById = new HashMap<>();
mPackagesByName = new HashMap<>();
mAuxiliaryResSpecs = new LinkedHashMap<>();
mAuxiliaryResSpecsByName = new LinkedHashMap<>();
mMainPackages = new LinkedHashSet<>();
mFramePackages = new LinkedHashSet<>();
}
Expand Down Expand Up @@ -91,6 +95,16 @@ public ResResSpec getResSpec(int resID) throws AndrolibException {
}

public ResResSpec getResSpec(ResID resID) throws AndrolibException {
ResPackage pkg = mPackagesById.get(resID.pkgId);
if (pkg != null && pkg.hasResSpec(resID)) {
return pkg.getResSpec(resID);
}

ResResSpec auxiliarySpec = mAuxiliaryResSpecs.get(resID);
if (auxiliarySpec != null) {
return auxiliarySpec;
}

return getPackage(resID.pkgId).getResSpec(resID);
}

Expand Down Expand Up @@ -131,29 +145,27 @@ private ResPackage selectPkgWithMostResSpecs(ResPackage[] pkgs) {
}

public void loadMainPkg(ExtFile apkFile) throws AndrolibException {
LOGGER.info("Loading resource table...");
ResPackage[] pkgs = loadResPackagesFromApk(apkFile, mConfig.keepBrokenResources);
ResPackage pkg;

switch (pkgs.length) {
case 0:
pkg = new ResPackage(this, 0, null);
break;
case 1:
pkg = pkgs[0];
break;
case 2:
LOGGER.warning("Skipping package group: " + pkgs[0].getName());
pkg = pkgs[1];
break;
default:
pkg = selectPkgWithMostResSpecs(pkgs);
break;
if (mMainPkgLoaded) {
return;
}

LOGGER.info("Loading resource table...");
ResPackage pkg = selectPkg(loadResPackagesFromApk(apkFile, mConfig.keepBrokenResources));
addPackage(pkg, true);
mMainPkgLoaded = true;
}

public void loadAuxiliaryPkg(ExtFile apkFile) throws AndrolibException {
LOGGER.info("Loading auxiliary resource table from file: " + apkFile);
addAuxiliaryPackage(selectPkg(loadResPackagesFromApk(apkFile, mConfig.keepBrokenResources)));
}

public void loadAuxiliaryPkgs(Collection<ExtFile> apkFiles) throws AndrolibException {
for (ExtFile apkFile : apkFiles) {
loadAuxiliaryPkg(apkFile);
}
}

private ResPackage loadFrameworkPkg(int id) throws AndrolibException {
Framework framework = new Framework(mConfig);
File frameworkApk = framework.getFrameworkApk(id, mConfig.frameworkTag);
Expand Down Expand Up @@ -224,7 +236,32 @@ public ResPackage getPackage(String name) throws AndrolibException {
}

public ResValue getValue(String pkg, String type, String name) throws AndrolibException {
return getPackage(pkg).getType(type).getResSpec(name).getDefaultResource().getValue();
try {
return getPackage(pkg).getType(type).getResSpec(name).getDefaultResource().getValue();
} catch (UndefinedResObjectException ex) {
ResResSpec auxiliarySpec = mAuxiliaryResSpecsByName.get(getSpecNameKey(pkg, type, name));
if (auxiliarySpec == null) {
throw ex;
}
return auxiliarySpec.getDefaultResource().getValue();
}
}

public Collection<ResResSpec> listResSpecs(ResPackage pkg, boolean includeAuxiliary) {
if (!includeAuxiliary) {
return pkg.listResSpecs();
}

Map<ResID, ResResSpec> specs = new LinkedHashMap<>();
for (ResResSpec spec : pkg.listResSpecs()) {
specs.put(spec.getId(), spec);
}
for (ResResSpec spec : mAuxiliaryResSpecs.values()) {
if (spec.getId().pkgId == pkg.getId()) {
specs.putIfAbsent(spec.getId(), spec);
}
}
return specs.values();
}

public void addPackage(ResPackage pkg, boolean main) throws AndrolibException {
Expand All @@ -246,6 +283,12 @@ public void addPackage(ResPackage pkg, boolean main) throws AndrolibException {
}
}

void addAuxiliaryPackage(ResPackage pkg) {
for (ResResSpec spec : pkg.listResSpecs()) {
addAuxiliaryResSpec(spec);
}
}

public void setPackageRenamed(String pkg) {
mPackageRenamed = pkg;
}
Expand Down Expand Up @@ -381,4 +424,44 @@ private void loadVersionName(File apkDir) {
mApkInfo.versionInfo.versionName = refValue;
}
}

private ResPackage selectPkg(ResPackage[] pkgs) {
switch (pkgs.length) {
case 0:
return new ResPackage(this, 0, null);
case 1:
return pkgs[0];
case 2:
LOGGER.warning("Skipping package group: " + pkgs[0].getName());
return pkgs[1];
default:
return selectPkgWithMostResSpecs(pkgs);
}
}

private void addAuxiliaryResSpec(ResResSpec spec) {
ResResSpec existingSpec = mAuxiliaryResSpecs.get(spec.getId());
if (existingSpec != null) {
if (!existingSpec.getName().equals(spec.getName())
|| !existingSpec.getType().getName().equals(spec.getType().getName())) {
LOGGER.warning("Ignoring conflicting auxiliary resource spec: " + spec);
}
return;
}

mAuxiliaryResSpecs.put(spec.getId(), spec);

String key = getSpecNameKey(spec.getPackage().getName(), spec.getType().getName(), spec.getName());
ResResSpec existingNamedSpec = mAuxiliaryResSpecsByName.get(key);
if (existingNamedSpec != null && !existingNamedSpec.getId().equals(spec.getId())) {
LOGGER.warning("Ignoring conflicting auxiliary resource name: " + key);
return;
}

mAuxiliaryResSpecsByName.putIfAbsent(key, spec);
}

private String getSpecNameKey(String pkg, String type, String name) {
return pkg + ":" + type + "/" + name;
}
}