releasetools: Fix an issue in GetMinSdkVersion.

The following is a buggy pattern that won't capture anything into err.
The issue is benign, since a failed run would be eventually captured by
a subsequent check.

  p = Run(["aapt", ...], stdout=subprocess.PIPE)
  output, err = p.communicate()
  if err:
    raise ...

This CL changes the error detection to be based on the return code from
aapt. It also adds some sanity test to ensure the call to aapt works.
The test app is built from AOSP com.android.cts.ctsshim (chosen mostly
because of its small size).

Test: python -m unittest test_common
Change-Id: I337f141bd0fc5f0801dfc628c601b88b7640789c
This commit is contained in:
Tao Bao 2018-03-21 23:28:51 -07:00
parent 2ebcf419e4
commit f47bf0fecf
3 changed files with 56 additions and 16 deletions

View File

@ -718,18 +718,31 @@ def GetKeyPasswords(keylist):
def GetMinSdkVersion(apk_name):
"""Get the minSdkVersion delared in the APK. This can be both a decimal number
(API Level) or a codename.
"""Gets the minSdkVersion declared in the APK.
It calls 'aapt' to query the embedded minSdkVersion from the given APK file.
This can be both a decimal number (API Level) or a codename.
Args:
apk_name: The APK filename.
Returns:
The parsed SDK version string.
Raises:
ExternalError: On failing to obtain the min SDK version.
"""
proc = Run(
["aapt", "dump", "badging", apk_name], stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdoutdata, stderrdata = proc.communicate()
if proc.returncode != 0:
raise ExternalError(
"Failed to obtain minSdkVersion: aapt return code {}:\n{}\n{}".format(
proc.returncode, stdoutdata, stderrdata))
p = Run(["aapt", "dump", "badging", apk_name], stdout=subprocess.PIPE)
output, err = p.communicate()
if err:
raise ExternalError("Failed to obtain minSdkVersion: aapt return code %s"
% (p.returncode,))
for line in output.split("\n"):
# Looking for lines such as sdkVersion:'23' or sdkVersion:'M'
for line in stdoutdata.split("\n"):
# Looking for lines such as sdkVersion:'23' or sdkVersion:'M'.
m = re.match(r'sdkVersion:\'([^\']*)\'', line)
if m:
return m.group(1)
@ -737,11 +750,20 @@ def GetMinSdkVersion(apk_name):
def GetMinSdkVersionInt(apk_name, codename_to_api_level_map):
"""Get the minSdkVersion declared in the APK as a number (API Level). If
minSdkVersion is set to a codename, it is translated to a number using the
provided map.
"""
"""Returns the minSdkVersion declared in the APK as a number (API Level).
If minSdkVersion is set to a codename, it is translated to a number using the
provided map.
Args:
apk_name: The APK filename.
Returns:
The parsed SDK version number.
Raises:
ExternalError: On failing to get the min SDK version number.
"""
version = GetMinSdkVersion(apk_name)
try:
return int(version)
@ -750,8 +772,9 @@ def GetMinSdkVersionInt(apk_name, codename_to_api_level_map):
if version in codename_to_api_level_map:
return codename_to_api_level_map[version]
else:
raise ExternalError("Unknown minSdkVersion: '%s'. Known codenames: %s"
% (version, codename_to_api_level_map))
raise ExternalError(
"Unknown minSdkVersion: '{}'. Known codenames: {}".format(
version, codename_to_api_level_map))
def SignFile(input_name, output_name, key, password, min_api_level=None,

View File

@ -504,6 +504,23 @@ class CommonApkUtilsTest(unittest.TestCase):
actual = common.ParseCertificate(cert_fp.read())
self.assertEqual(expected, actual)
def test_GetMinSdkVersion(self):
test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
self.assertEqual('24', common.GetMinSdkVersion(test_app))
def test_GetMinSdkVersion_invalidInput(self):
self.assertRaises(
common.ExternalError, common.GetMinSdkVersion, 'does-not-exist.apk')
def test_GetMinSdkVersionInt(self):
test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
self.assertEqual(24, common.GetMinSdkVersionInt(test_app, {}))
def test_GetMinSdkVersionInt_invalidInput(self):
self.assertRaises(
common.ExternalError, common.GetMinSdkVersionInt, 'does-not-exist.apk',
{})
class CommonUtilsTest(unittest.TestCase):

BIN
tools/releasetools/testdata/TestApp.apk vendored Normal file

Binary file not shown.