From d98d8c2e52b3d4e352032e549f4b319a8a890476 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 11 Mar 2018 22:09:09 +0100 Subject: [PATCH 1/4] update: do not crash with androguard when working with apps without icons For example, SpeedoMeterApp.main_1.apk --- fdroidserver/update.py | 8 +++++--- tests/SpeedoMeterApp.main_1.apk | Bin 0 -> 7299 bytes tests/update.TestCase | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 tests/SpeedoMeterApp.main_1.apk diff --git a/fdroidserver/update.py b/fdroidserver/update.py index c22ac0f3..168ef31f 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1223,9 +1223,11 @@ def scan_apk_androguard(apk, apkfile): if apkobject.get_target_sdk_version() is not None: apk['targetSdkVersion'] = apkobject.get_target_sdk_version() - icon_id = int(apkobject.get_element("application", "icon").replace("@", "0x"), 16) - icon_name = arsc.get_id(apk['packageName'], icon_id)[1] - apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name) + icon_id_str = apkobject.get_element("application", "icon") + if icon_id_str: + icon_id = int(icon_id_str.replace("@", "0x"), 16) + icon_name = arsc.get_id(apk['packageName'], icon_id)[1] + apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name) arch_re = re.compile("^lib/(.*)/.*$") arch = set([arch_re.match(file).group(1) for file in apkobject.get_files() if arch_re.match(file)]) diff --git a/tests/SpeedoMeterApp.main_1.apk b/tests/SpeedoMeterApp.main_1.apk new file mode 100644 index 0000000000000000000000000000000000000000..2ce7b362968b84f5f3cffda58304f80cc651d3b8 GIT binary patch literal 7299 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 S0&FKScxZr8I@<+o?LPq8Y=nvc literal 0 HcmV?d00001 diff --git a/tests/update.TestCase b/tests/update.TestCase index 2e9b687b..03391c18 100755 --- a/tests/update.TestCase +++ b/tests/update.TestCase @@ -333,6 +333,9 @@ class UpdateTest(unittest.TestCase): '320': 'res/drawable-xhdpi-v4/icon.png', '-1': 'res/drawable-mdpi-v4/icon.png'}) + apk_info = fdroidserver.update.scan_apk('SpeedoMeterApp.main_1.apk') + self.assertEqual(apk_info['icons_src'], {}) + def test_scan_apk_no_sig(self): config = dict() fdroidserver.common.fill_config_defaults(config) From 2c8008356bbc23b3c0010d93ccea5dce036d92b1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 11 Mar 2018 22:10:46 +0100 Subject: [PATCH 2/4] update: handle bad XML when using androguard repo/ch.swift.willi_417101.apk had a C/Java comment in the AndroidManifest.xml rather than an XML comment: // Remove permissions introduced by the appsflyer library --- fdroidserver/update.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 168ef31f..7203fbcc 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1264,7 +1264,10 @@ def scan_apk_androguard(apk, apkfile): apk['uses-permission-sdk-23'].append(permission_sdk_23) for item in xml.findall('uses-feature'): - feature = str(item.attrib['{' + xml.nsmap['android'] + '}name']) + key = '{' + xml.nsmap['android'] + '}name' + if key not in item.attrib: + continue + feature = str(item.attrib[key]) if feature != "android.hardware.screen.portrait" \ and feature != "android.hardware.screen.landscape": if feature.startswith("android.feature."): From e89478e52961457334e65dbd4705ebe752c79241 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 13 Mar 2018 11:19:19 +0100 Subject: [PATCH 3/4] update: do not crash on APKs without icons when using androguard --- fdroidserver/update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 7203fbcc..fa2ba8d1 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1095,7 +1095,7 @@ def _get_apk_icons_src(apkfile, icon_name): else: density = '160' icons_src[density] = m.group(0) - if icons_src.get('-1') is None: + if icons_src.get('-1') is None and '160' in icons_src: icons_src['-1'] = icons_src['160'] return icons_src From 3b09e5ee082bd3a04bc76bd2b64fa57ac16a5994 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 13 Mar 2018 12:13:23 +0100 Subject: [PATCH 4/4] update: do not crash on android-26+ XML icon For example: res/drawable-v26/icon.xml Here's the full range of possibilities, we have a lot of work to do: $ for f in */*.apk; do unzip -l $f |grep -F icon.| grep -Eo 'res/drawable[^/]*'; done | sort -u res/drawable res/drawable-anydpi-v21 res/drawable-anydpi-v26 res/drawable-hdpi res/drawable-hdpi-v11 res/drawable-hdpi-v12 res/drawable-hdpi-v4 res/drawable-hdpi-v5 res/drawable-hdpi-v6 res/drawable-hdpi-v9 res/drawable-large res/drawable-large-hdpi-v11 res/drawable-large-hdpi-v4 res/drawable-large-ldpi-v4 res/drawable-large-mdpi res/drawable-large-mdpi-v11 res/drawable-large-v4 res/drawable-large-xhdpi-v11 res/drawable-large-xhdpi-v4 res/drawable-large-xxhdpi-v11 res/drawable-large-xxhdpi-v4 res/drawable-ldpi res/drawable-ldpi-v11 res/drawable-ldpi-v4 res/drawable-ldpi-v5 res/drawable-ldpi-v6 res/drawable-ldpi-v9 res/drawable-ldrtl-v17 res/drawable-mdpi res/drawable-mdpi-v11 res/drawable-mdpi-v12 res/drawable-mdpi-v4 res/drawable-mdpi-v5 res/drawable-mdpi-v6 res/drawable-mdpi-v9 res/drawable-nodpi res/drawable-nodpi-v4 res/drawable-tvdpi-v4 res/drawable-v11 res/drawable-v14 res/drawable-v21 res/drawable-xhdpi res/drawable-xhdpi-v11 res/drawable-xhdpi-v12 res/drawable-xhdpi-v4 res/drawable-xhdpi-v9 res/drawable-xlarge-hdpi res/drawable-xlarge-hdpi-v4 res/drawable-xlarge-mdpi res/drawable-xlarge-mdpi-v4 res/drawable-xlarge-v4 res/drawable-xlarge-xhdpi-v4 res/drawable-xxhdpi res/drawable-xxhdpi-v11 res/drawable-xxhdpi-v21 res/drawable-xxhdpi-v4 res/drawable-xxhdpi-v9 res/drawable-xxxhdpi res/drawable-xxxhdpi-v11 res/drawable-xxxhdpi-v4 --- fdroidserver/update.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index fa2ba8d1..af731dd1 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -60,6 +60,7 @@ APK_PERMISSION_PAT = \ APK_FEATURE_PAT = re.compile(".*name='([^']*)'.*") screen_densities = ['65534', '640', '480', '320', '240', '160', '120'] +# resolutions must end with 'dpi' screen_resolutions = { "xxxhdpi": '640', "xxhdpi": '480', @@ -67,7 +68,7 @@ screen_resolutions = { "hdpi": '240', "mdpi": '160', "ldpi": '120', - "undefined": '-1', + "undefineddpi": '-1', "anydpi": '65534', "nodpi": '65535' } @@ -1090,7 +1091,7 @@ def _get_apk_icons_src(apkfile, icon_name): m = density_re.match(filename) if m: folder = m.group(1).split('-') - if len(folder) > 1: + if len(folder) > 1 and folder[1].endswith('dpi'): density = screen_resolutions[folder[1]] else: density = '160'